From 251630590d1e666da57443bf12fdcbba6c8e653f Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 7 Feb 2014 17:01:08 -0800 Subject: [PATCH 001/597] Initial port. --- .gitattributes | 50 + .gitignore | 22 + KatanaInternal.sln | 94 + NuGet.Config | 13 + build.cmd | 23 + global.json | 3 + makefile.shade | 7 + samples/HelloWorld/Program.cs | 55 + samples/HelloWorld/project.json | 10 + samples/SelfHostServer/App.config | 9 + samples/SelfHostServer/Program.cs | 138 + .../SelfHostServer/Properties/AssemblyInfo.cs | 42 + samples/SelfHostServer/Public/1kb.txt | 1 + samples/SelfHostServer/packages.config | 8 + samples/SelfHostServer/project.json | 19 + samples/TestClient/App.config | 6 + samples/TestClient/Program.cs | 78 + samples/TestClient/Properties/AssemblyInfo.cs | 36 + samples/TestClient/TestClient.csproj | 62 + .../AuthTypes.cs | 37 + .../ComNetOS.cs | 38 + .../Constants.cs | 44 + .../DictionaryExtensions.cs | 67 + .../DigestCache.cs | 153 + .../DisconnectAsyncResult.cs | 93 + .../HeaderEncoding.cs | 139 + .../HttpKnownHeaderNames.cs | 75 + .../HttpStatusCode.cs | 314 ++ .../Legacy/CaseInsinsitiveAscii.cs | 133 + .../Legacy/GlobalLog.cs | 689 +++++ .../Legacy/HttpListenerContext.cs | 67 + .../Legacy/Internal.cs | 286 ++ .../Legacy/Logging.cs | 657 +++++ .../Legacy/LoggingObject.cs | 580 ++++ .../Legacy/SR.cs | 630 ++++ .../Legacy/ValidationHelper.cs | 74 + .../NTAuthentication.cs | 721 +++++ .../NativeInterop/AuthIdentity.cs | 40 + .../NativeInterop/ContextFlags.cs | 124 + .../NativeInterop/NativeSSPI.cs | 42 + .../NativeInterop/SSPIAuthType.cs | 302 ++ .../NativeInterop/SSPIHandle.cs | 36 + .../NativeInterop/SSPISessionCache.cs | 49 + .../NativeInterop/SSPIWrapper.cs | 462 +++ .../NativeInterop/SafeCloseHandle.cs | 51 + .../NativeInterop/SafeCredentialReference.cs | 69 + .../NativeInterop/SafeDeleteContext.cs | 707 +++++ .../NativeInterop/SafeFreeCertContext.cs | 35 + .../NativeInterop/SafeFreeContextBuffer.cs | 148 + .../SafeFreeContextBufferChannelBinding.cs | 89 + .../NativeInterop/SafeFreeCredentials.cs | 199 ++ .../NativeInterop/SafeLocalFree.cs | 48 + .../NativeInterop/SafeSspiAuthDataHandle.cs | 32 + .../NativeInterop/SchProtocols.cs | 41 + .../NativeInterop/SecSizes.cs | 44 + .../NativeInterop/SecurityBuffer.cs | 56 + .../NativeInterop/SecurityBufferDescriptor.cs | 33 + .../NativeInterop/SecurityPackageInfoClass.cs | 80 + .../NativeInterop/SslConnectionInfo.cs | 38 + .../NativeInterop/StreamSizes.cs | 43 + .../NativeInterop/UnsafeNativeMethods.cs | 222 ++ .../NegotiationInfoClass.cs | 70 + .../PrefixCollection.cs | 109 + .../PrefixEnumerator.cs | 51 + .../Properties/AssemblyInfo.cs | 42 + .../ServiceNameStore.cs | 368 +++ .../WindowsAuthMiddleware.cs | 1281 +++++++++ .../packages.config | 4 + .../project.json | 14 + .../AsyncAcceptContext.cs | 224 ++ .../AuthenticationManager.cs | 129 + .../AuthenticationTypes.cs | 19 + .../Constants.cs | 63 + .../CustomDictionary.xml | 10 + .../DictionaryExtensions.cs | 51 + .../GlobalSuppressions.cs | Bin 0 -> 1926 bytes .../Helpers.cs | 29 + .../LogHelper.cs | 82 + .../NativeInterop/AddressFamily.cs | 172 ++ .../NativeInterop/ComNetOS.cs | 26 + .../NativeInterop/ContextAttribute.cs | 56 + .../NativeInterop/HttpRequestQueueV2Handle.cs | 25 + .../NativeInterop/HttpServerSessionHandle.cs | 48 + .../NativeInterop/HttpSysRequestHeader.cs | 54 + .../NativeInterop/HttpSysResponseHeader.cs | 43 + .../NativeInterop/HttpSysSettings.cs | 125 + .../NativeInterop/IntPtrHelper.cs | 23 + .../NativeInterop/NclUtilities.cs | 25 + .../NativeInterop/SSPIHandle.cs | 34 + .../NativeInterop/SafeLoadLibrary.cs | 42 + .../NativeInterop/SafeLocalFree.cs | 46 + .../SafeLocalFreeChannelBinding.cs | 42 + .../NativeInterop/SafeLocalMemHandle.cs | 30 + .../NativeInterop/SafeNativeOverlapped.cs | 68 + .../NativeInterop/SchProtocols.cs | 51 + .../NativeInterop/SecurityStatus.cs | 54 + .../NativeInterop/SocketAddress.cs | 342 +++ .../NativeInterop/UnsafeNativeMethods.cs | 1129 ++++++++ .../OwinServerFactory.cs | 108 + .../OwinWebListener.cs | 1107 +++++++ .../Prefix.cs | 102 + .../Properties/AssemblyInfo.cs | 44 + .../PumpLimits.cs | 31 + .../RequestProcessing/BoundaryType.cs | 18 + .../CallEnvironment.Generated.cs | 1913 +++++++++++++ .../CallEnvironment.Generated.tt | 316 ++ .../RequestProcessing/CallEnvironment.cs | 165 ++ .../RequestProcessing/ClientCertLoader.cs | 347 +++ .../RequestProcessing/EntitySendFormat.cs | 17 + .../RequestProcessing/HeaderEncoding.cs | 97 + .../RequestProcessing/HttpKnownHeaderNames.cs | 75 + .../RequestProcessing/HttpReasonPhrase.cs | 109 + .../RequestProcessing/HttpStatusCode.cs | 314 ++ .../RequestProcessing/NativeRequestContext.cs | 170 ++ .../RequestProcessing/NilEnvDictionary.cs | 115 + .../RequestProcessing/OpaqueStream.cs | 168 ++ .../RequestProcessing/Request.cs | 456 +++ .../RequestProcessing/RequestContext.cs | 388 +++ .../RequestHeaders.Generated.cs | 2544 +++++++++++++++++ .../RequestHeaders.Generated.tt | 218 ++ .../RequestProcessing/RequestHeaders.cs | 167 ++ .../RequestProcessing/RequestStream.cs | 614 ++++ .../RequestProcessing/RequestUriBuilder.cs | 569 ++++ .../RequestProcessing/Response.cs | 756 +++++ .../RequestProcessing/ResponseStream.cs | 826 ++++++ .../ResponseStreamAsyncResult.cs | 441 +++ .../RequestProcessing/SslStatus.cs | 15 + .../Resources.Designer.cs | 153 + .../Resources.resx | 150 + .../TimeoutManager.cs | 267 ++ .../ValidationHelper.cs | 67 + .../WebListenerException.cs | 44 + .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 32 + .../SafeHandleZeroOrMinusOneIsInvalid.cs | 31 + .../System/ComponentModel/Win32Exception.cs | 112 + .../fx/System/Diagnostics/TraceEventType.cs | 35 + .../fx/System/ExternDll.cs | 16 + .../InteropServices/ExternalException.cs | 98 + .../fx/System/SafeNativeMethods.cs | 28 + .../ExtendedProtection/ChannelBinding.cs | 33 + .../project.json | 8 + src/Microsoft.AspNet.WebSockets/Constants.cs | 21 + .../HttpKnownHeaderNames.cs | 76 + .../Legacy/HttpListenerContext.cs | 58 + .../Legacy/HttpListenerRequest.cs | 66 + src/Microsoft.AspNet.WebSockets/Legacy/SR.cs | 66 + .../WebSocketHttpListenerDuplexStream.cs | 1262 ++++++++ .../NativeInterop/SafeLoadLibrary.cs | 40 + .../NativeInterop/SafeNativeOverlapped.cs | 80 + .../NativeInterop/SafeWebSocketHandle.cs | 32 + .../NativeInterop/UnsafeNativeMethods.cs | 842 ++++++ .../OwinWebSocketWrapper.cs | 137 + .../Properties/AssemblyInfo.cs | 36 + .../ServerWebSocket.cs | 62 + src/Microsoft.AspNet.WebSockets/WebSocket.cs | 124 + .../WebSocketBase.cs | 2481 ++++++++++++++++ .../WebSocketBuffer.cs | 698 +++++ .../WebSocketCloseStatus.cs | 40 + .../WebSocketError.cs | 22 + .../WebSocketException.cs | 155 + .../WebSocketExtensions.cs | 14 + .../WebSocketHelpers.cs | 522 ++++ .../WebSocketMessageType.cs | 15 + .../WebSocketMiddleware.cs | 167 ++ .../WebSocketReceiveResult.cs | 55 + .../WebSocketState.cs | 19 + src/Microsoft.AspNet.WebSockets/build.cmd | 3 + .../SafeHandleZeroOrMinusOneIsInvalid.cs | 31 + .../fx/System/AccessViolationException.cs | 16 + .../System/ComponentModel/Win32Exception.cs | 112 + .../fx/System/ExternDll.cs | 16 + .../InteropServices/ExternalException.cs | 98 + .../fx/System/SafeNativeMethods.cs | 28 + .../fx/System/SystemException.cs | 16 + .../packages.config | 5 + src/Microsoft.AspNet.WebSockets/project.json | 17 + .../DenyAnonymous.cs | 47 + .../DictionaryExtensions.cs | 51 + .../DigestTests.cs | 244 ++ .../NegotiateTests.cs | 261 ++ .../PassThroughTests.cs | 64 + .../Properties/AssemblyInfo.cs | 42 + .../packages.config | 5 + .../project.json | 17 + .../AuthenticationTests.cs | 136 + .../DictionaryExtensions.cs | 31 + .../HttpsTests.cs | 191 ++ .../OpaqueUpgradeTests.cs | 324 +++ .../Properties/AssemblyInfo.cs | 42 + .../RequestBodyTests.cs | 176 ++ .../RequestHeaderTests.cs | 120 + .../RequestTests.cs | 185 ++ .../ResponseBodyTests.cs | 213 ++ .../ResponseHeaderTests.cs | 243 ++ .../ResponseSendFileTests.cs | 327 +++ .../ResponseTests.cs | 142 + .../ServerTests.cs | 287 ++ .../project.json | 16 + 198 files changed, 37324 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 KatanaInternal.sln create mode 100644 NuGet.Config create mode 100644 build.cmd create mode 100644 global.json create mode 100644 makefile.shade create mode 100644 samples/HelloWorld/Program.cs create mode 100644 samples/HelloWorld/project.json create mode 100644 samples/SelfHostServer/App.config create mode 100644 samples/SelfHostServer/Program.cs create mode 100644 samples/SelfHostServer/Properties/AssemblyInfo.cs create mode 100644 samples/SelfHostServer/Public/1kb.txt create mode 100644 samples/SelfHostServer/packages.config create mode 100644 samples/SelfHostServer/project.json create mode 100644 samples/TestClient/App.config create mode 100644 samples/TestClient/Program.cs create mode 100644 samples/TestClient/Properties/AssemblyInfo.cs create mode 100644 samples/TestClient/TestClient.csproj create mode 100644 src/Microsoft.AspNet.Security.Windows/AuthTypes.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/ComNetOS.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Constants.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/DigestCache.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs create mode 100644 src/Microsoft.AspNet.Security.Windows/packages.config create mode 100644 src/Microsoft.AspNet.Security.Windows/project.json create mode 100644 src/Microsoft.AspNet.Server.WebListener/AsyncAcceptContext.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/AuthenticationManager.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/AuthenticationTypes.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/Constants.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/CustomDictionary.xml create mode 100644 src/Microsoft.AspNet.Server.WebListener/DictionaryExtensions.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/GlobalSuppressions.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/Helpers.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/LogHelper.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/AddressFamily.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/ComNetOS.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/ContextAttribute.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpRequestQueueV2Handle.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpServerSessionHandle.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysRequestHeader.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysResponseHeader.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysSettings.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/IntPtrHelper.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/NclUtilities.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SSPIHandle.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLoadLibrary.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFree.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFreeChannelBinding.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalMemHandle.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeNativeOverlapped.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SchProtocols.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SecurityStatus.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/Prefix.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.tt create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HeaderEncoding.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpKnownHeaderNames.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpReasonPhrase.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpStatusCode.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NativeRequestContext.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NilEnvDictionary.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/OpaqueStream.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.tt create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestUriBuilder.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/SslStatus.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/Resources.Designer.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/Resources.resx create mode 100644 src/Microsoft.AspNet.Server.WebListener/TimeoutManager.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/ValidationHelper.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/System/Diagnostics/TraceEventType.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/System/ExternDll.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/System/Runtime/InteropServices/ExternalException.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/System/SafeNativeMethods.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/project.json create mode 100644 src/Microsoft.AspNet.WebSockets/Constants.cs create mode 100644 src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs create mode 100644 src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs create mode 100644 src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs create mode 100644 src/Microsoft.AspNet.WebSockets/Legacy/SR.cs create mode 100644 src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs create mode 100644 src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs create mode 100644 src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs create mode 100644 src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs create mode 100644 src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs create mode 100644 src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs create mode 100644 src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocket.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketBase.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketError.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketException.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs create mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketState.cs create mode 100644 src/Microsoft.AspNet.WebSockets/build.cmd create mode 100644 src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs create mode 100644 src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs create mode 100644 src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs create mode 100644 src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs create mode 100644 src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs create mode 100644 src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs create mode 100644 src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs create mode 100644 src/Microsoft.AspNet.WebSockets/packages.config create mode 100644 src/Microsoft.AspNet.WebSockets/project.json create mode 100644 test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs create mode 100644 test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs create mode 100644 test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs create mode 100644 test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs create mode 100644 test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs create mode 100644 test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs create mode 100644 test/Microsoft.AspNet.Security.Windows.Test/packages.config create mode 100644 test/Microsoft.AspNet.Security.Windows.Test/project.json create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/DictionaryExtensions.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/project.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..bdaa5ba982 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,50 @@ +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain + +*.jpg binary +*.png binary +*.gif binary + +*.cs text=auto diff=csharp +*.vb text=auto +*.resx text=auto +*.c text=auto +*.cpp text=auto +*.cxx text=auto +*.h text=auto +*.hxx text=auto +*.py text=auto +*.rb text=auto +*.java text=auto +*.html text=auto +*.htm text=auto +*.css text=auto +*.scss text=auto +*.sass text=auto +*.less text=auto +*.js text=auto +*.lisp text=auto +*.clj text=auto +*.sql text=auto +*.php text=auto +*.lua text=auto +*.m text=auto +*.asm text=auto +*.erl text=auto +*.fs text=auto +*.fsx text=auto +*.hs text=auto + +*.csproj text=auto +*.vbproj text=auto +*.fsproj text=auto +*.dbproj text=auto +*.sln text=auto eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..2554a1fc23 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +[Oo]bj/ +[Bb]in/ +TestResults/ +.nuget/ +_ReSharper.*/ +packages/ +artifacts/ +PublishProfiles/ +*.user +*.suo +*.cache +*.docstates +_ReSharper.* +nuget.exe +*net45.csproj +*k10.csproj +*.psess +*.vsp +*.pidb +*.userprefs +*DS_Store +*.ncrunchsolution diff --git a/KatanaInternal.sln b/KatanaInternal.sln new file mode 100644 index 0000000000..9f18ac98c5 --- /dev/null +++ b/KatanaInternal.sln @@ -0,0 +1,94 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30110.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.k10", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.k10.csproj", "{6D9D3023-3ED7-4C95-80F0-347843ABD759}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.net45", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.net45.csproj", "{253B9134-B6EB-4E59-8725-D983FD941A21}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebSockets.net45", "src\Microsoft.AspNet.WebSockets\Microsoft.AspNet.WebSockets.net45.csproj", "{00C6A882-1FE2-4769-901C-023D8DC175C4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{99D5E5F3-88F5-4CCF-8D8C-717C8925DF09}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E183C826-1360-4DFF-9994-F33CED5C8525}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A1E31E3-2794-4CA3-B8E2-253E96BDE514}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld.net45", "samples\HelloWorld\HelloWorld.net45.csproj", "{BF335732-BB09-49A1-8676-F074047E7DB2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelfHostServer.net45", "samples\SelfHostServer\SelfHostServer.net45.csproj", "{96C67B2F-9913-4E8D-B2E8-969BE66B71B6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.Test.net45", "test\Microsoft.AspNet.Server.WebListener.Test\Microsoft.AspNet.Server.WebListener.Test.net45.csproj", "{485DAC59-A1F1-4D47-98BF-B448C994E05B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld.k10", "samples\HelloWorld\HelloWorld.k10.csproj", "{A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.Windows.net45", "src\Microsoft.AspNet.Security.Windows\Microsoft.AspNet.Security.Windows.net45.csproj", "{8B4EF749-251D-4222-AD18-DE5A1E7D321A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.Windows.Test.net45", "test\Microsoft.AspNet.Security.Windows.Test\Microsoft.AspNet.Security.Windows.Test.net45.csproj", "{3EC418D5-C8FD-47AA-BFED-F524358EC3DD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Any CPU.Build.0 = Release|Any CPU + {6D9D3023-3ED7-4C95-80F0-347843ABD759}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D9D3023-3ED7-4C95-80F0-347843ABD759}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D9D3023-3ED7-4C95-80F0-347843ABD759}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D9D3023-3ED7-4C95-80F0-347843ABD759}.Release|Any CPU.Build.0 = Release|Any CPU + {253B9134-B6EB-4E59-8725-D983FD941A21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {253B9134-B6EB-4E59-8725-D983FD941A21}.Debug|Any CPU.Build.0 = Debug|Any CPU + {253B9134-B6EB-4E59-8725-D983FD941A21}.Release|Any CPU.ActiveCfg = Release|Any CPU + {253B9134-B6EB-4E59-8725-D983FD941A21}.Release|Any CPU.Build.0 = Release|Any CPU + {00C6A882-1FE2-4769-901C-023D8DC175C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00C6A882-1FE2-4769-901C-023D8DC175C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00C6A882-1FE2-4769-901C-023D8DC175C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00C6A882-1FE2-4769-901C-023D8DC175C4}.Release|Any CPU.Build.0 = Release|Any CPU + {BF335732-BB09-49A1-8676-F074047E7DB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF335732-BB09-49A1-8676-F074047E7DB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF335732-BB09-49A1-8676-F074047E7DB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF335732-BB09-49A1-8676-F074047E7DB2}.Release|Any CPU.Build.0 = Release|Any CPU + {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Release|Any CPU.Build.0 = Release|Any CPU + {485DAC59-A1F1-4D47-98BF-B448C994E05B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {485DAC59-A1F1-4D47-98BF-B448C994E05B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {485DAC59-A1F1-4D47-98BF-B448C994E05B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {485DAC59-A1F1-4D47-98BF-B448C994E05B}.Release|Any CPU.Build.0 = Release|Any CPU + {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Release|Any CPU.Build.0 = Release|Any CPU + {8B4EF749-251D-4222-AD18-DE5A1E7D321A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B4EF749-251D-4222-AD18-DE5A1E7D321A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B4EF749-251D-4222-AD18-DE5A1E7D321A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B4EF749-251D-4222-AD18-DE5A1E7D321A}.Release|Any CPU.Build.0 = Release|Any CPU + {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {485DAC59-A1F1-4D47-98BF-B448C994E05B} = {E183C826-1360-4DFF-9994-F33CED5C8525} + {3EC418D5-C8FD-47AA-BFED-F524358EC3DD} = {E183C826-1360-4DFF-9994-F33CED5C8525} + {8B828433-B333-4C19-96AE-00BFFF9D8841} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {BF335732-BB09-49A1-8676-F074047E7DB2} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {96C67B2F-9913-4E8D-B2E8-969BE66B71B6} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {6D9D3023-3ED7-4C95-80F0-347843ABD759} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {253B9134-B6EB-4E59-8725-D983FD941A21} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {00C6A882-1FE2-4769-901C-023D8DC175C4} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {8B4EF749-251D-4222-AD18-DE5A1E7D321A} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + EndGlobalSection +EndGlobal diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000000..ab583b0ff7 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000000..7045ee1f84 --- /dev/null +++ b/build.cmd @@ -0,0 +1,23 @@ +@echo off +cd %~dp0 + +SETLOCAL +SET CACHED_NUGET=%LocalAppData%\NuGet\NuGet.exe + +IF EXIST %CACHED_NUGET% goto copynuget +echo Downloading latest version of NuGet.exe... +IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet +@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://www.nuget.org/nuget.exe' -OutFile '%CACHED_NUGET%'" + +:copynuget +IF EXIST .nuget\nuget.exe goto restore +md .nuget +copy %CACHED_NUGET% .nuget\nuget.exe > nul + +:restore +IF EXIST packages\KoreBuild goto run +.nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre +.nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion + +:run +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/global.json b/global.json new file mode 100644 index 0000000000..840c36f6ad --- /dev/null +++ b/global.json @@ -0,0 +1,3 @@ +{ + "sources": ["src"] +} \ No newline at end of file diff --git a/makefile.shade b/makefile.shade new file mode 100644 index 0000000000..6357ea2841 --- /dev/null +++ b/makefile.shade @@ -0,0 +1,7 @@ + +var VERSION='0.1' +var FULL_VERSION='0.1' +var AUTHORS='Microsoft' + +use-standard-lifecycle +k-standard-goals diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs new file mode 100644 index 0000000000..5e176ff7ee --- /dev/null +++ b/samples/HelloWorld/Program.cs @@ -0,0 +1,55 @@ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNet.Server.WebListener; + +using AppFunc = System.Func, System.Threading.Tasks.Task>; + +public class Program +{ + public static void Main(string[] args) + { + using (CreateServer(new AppFunc(HelloWorldApp))) + { + Console.WriteLine("Running, press enter to exit..."); + Console.ReadLine(); + } + } + + private static IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + public static Task HelloWorldApp(IDictionary environment) + { + string responseText = "Hello World"; + byte[] responseBytes = Encoding.UTF8.GetBytes(responseText); + + // See http://owin.org/spec/owin-1.0.0.html for standard environment keys. + Stream responseStream = (Stream)environment["owin.ResponseBody"]; + IDictionary responseHeaders = + (IDictionary)environment["owin.ResponseHeaders"]; + + responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) }; + responseHeaders["Content-Type"] = new string[] { "text/plain" }; + + return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length); + } +} diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json new file mode 100644 index 0000000000..63b0cd1595 --- /dev/null +++ b/samples/HelloWorld/project.json @@ -0,0 +1,10 @@ +{ + "version" : "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Server.WebListener" : "" + }, + "configurations": { + "net45": { }, + "k10" : { } + } +} diff --git a/samples/SelfHostServer/App.config b/samples/SelfHostServer/App.config new file mode 100644 index 0000000000..73c9881fb6 --- /dev/null +++ b/samples/SelfHostServer/App.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/samples/SelfHostServer/Program.cs b/samples/SelfHostServer/Program.cs new file mode 100644 index 0000000000..f01efdd682 --- /dev/null +++ b/samples/SelfHostServer/Program.cs @@ -0,0 +1,138 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Owin; +using Microsoft.AspNet.Server.WebListener; +using Microsoft.Owin.Hosting; +using Owin; + +namespace SelfHostServer +{ + // http://owin.org/extensions/owin-WebSocket-Extension-v0.4.0.htm + using WebSocketAccept = Action, // options + Func, Task>>; // callback + using WebSocketCloseAsync = + Func; + using WebSocketReceiveAsync = + Func /* data */, + CancellationToken /* cancel */, + Task>>; + using WebSocketReceiveResult = Tuple; // count + using WebSocketSendAsync = + Func /* data */, + int /* messageType */, + bool /* endOfMessage */, + CancellationToken /* cancel */, + Task>; + + public class Program + { + private static byte[] Data = new byte[1024]; + + public static void Main(string[] args) + { + using (WebApp.Start(new StartOptions( + // "http://localhost:5000/" + "https://localhost:9090/" + ) + { + ServerFactory = "Microsoft.AspNet.Server.WebListener" + })) + { + Console.WriteLine("Running, press any key to exit"); + // System.Diagnostics.Process.Start("http://localhost:5000/"); + Console.ReadKey(); + } + } + + public void Configuration(IAppBuilder app) + { + OwinWebListener listener = (OwinWebListener)app.Properties["Microsoft.AspNet.Server.WebListener.OwinWebListener"]; + listener.AuthenticationManager.AuthenticationTypes = + AuthenticationType.Basic | + AuthenticationType.Digest | + AuthenticationType.Negotiate | + AuthenticationType.Ntlm | + AuthenticationType.Kerberos; + + app.Use((context, next) => + { + Console.WriteLine("Request: " + context.Request.Uri); + return next(); + }); + app.Use((context, next) => + { + if (context.Request.User == null) + { + context.Response.StatusCode = 401; + return Task.FromResult(0); + } + else + { + Console.WriteLine(context.Request.User.Identity.AuthenticationType); + } + return next(); + }); + app.UseWebSockets(); + app.Use(UpgradeToWebSockets); + app.Run(Invoke); + } + + public Task Invoke(IOwinContext context) + { + context.Response.ContentLength = Data.Length; + return context.Response.WriteAsync(Data); + } + + // Run once per request + private Task UpgradeToWebSockets(IOwinContext context, Func next) + { + WebSocketAccept accept = context.Get("websocket.Accept"); + if (accept == null) + { + // Not a websocket request + return next(); + } + + accept(null, WebSocketEcho); + + return Task.FromResult(null); + } + + private async Task WebSocketEcho(IDictionary websocketContext) + { + var sendAsync = (WebSocketSendAsync)websocketContext["websocket.SendAsync"]; + var receiveAsync = (WebSocketReceiveAsync)websocketContext["websocket.ReceiveAsync"]; + var closeAsync = (WebSocketCloseAsync)websocketContext["websocket.CloseAsync"]; + var callCancelled = (CancellationToken)websocketContext["websocket.CallCancelled"]; + + byte[] buffer = new byte[1024]; + WebSocketReceiveResult received = await receiveAsync(new ArraySegment(buffer), callCancelled); + + object status; + while (!websocketContext.TryGetValue("websocket.ClientCloseStatus", out status) || (int)status == 0) + { + // Echo anything we receive + await sendAsync(new ArraySegment(buffer, 0, received.Item3), received.Item1, received.Item2, callCancelled); + + received = await receiveAsync(new ArraySegment(buffer), callCancelled); + } + + await closeAsync((int)websocketContext["websocket.ClientCloseStatus"], (string)websocketContext["websocket.ClientCloseDescription"], callCancelled); + } + } +} diff --git a/samples/SelfHostServer/Properties/AssemblyInfo.cs b/samples/SelfHostServer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..86b415a1b3 --- /dev/null +++ b/samples/SelfHostServer/Properties/AssemblyInfo.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SelfHostServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SelfHostServer")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ec50ddb4-9ec6-4cbd-96ac-15de948247cc")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("0.5")] +[assembly: AssemblyVersion("0.5")] +[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/samples/SelfHostServer/Public/1kb.txt b/samples/SelfHostServer/Public/1kb.txt new file mode 100644 index 0000000000..1d43866603 --- /dev/null +++ b/samples/SelfHostServer/Public/1kb.txt @@ -0,0 +1 @@ +asdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfqweruoiasdfnsngdfioenrglknsgilhasdgha;gu;agnaknusgnjkadfgnknjksdfk asdhfhasdf nklasdgnasg njagnjasdfasdfasdfasdfasdfasd \ No newline at end of file diff --git a/samples/SelfHostServer/packages.config b/samples/SelfHostServer/packages.config new file mode 100644 index 0000000000..b452be1749 --- /dev/null +++ b/samples/SelfHostServer/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json new file mode 100644 index 0000000000..ed203d2aeb --- /dev/null +++ b/samples/SelfHostServer/project.json @@ -0,0 +1,19 @@ +{ + "version" : "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Server.WebListener" : "", + "Microsoft.AspNet.WebSockets" : "" + }, + "configurations": { + "net45": { + "dependencies": { + "Owin": "1.0", + "Microsoft.Owin": "2.1.0", + "Microsoft.Owin.Diagnostics": "2.1.0", + "Microsoft.Owin.Hosting": "2.1.0", + "Microsoft.Owin.Host.HttpListener": "2.1.0", + "Microsoft.AspNet.AppBuilderSupport": "0.1-alpha-*" + } + } + } +} diff --git a/samples/TestClient/App.config b/samples/TestClient/App.config new file mode 100644 index 0000000000..8e15646352 --- /dev/null +++ b/samples/TestClient/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/samples/TestClient/Program.cs b/samples/TestClient/Program.cs new file mode 100644 index 0000000000..b1f93759aa --- /dev/null +++ b/samples/TestClient/Program.cs @@ -0,0 +1,78 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Net.WebSockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace TestClient +{ + public class Program + { + private const string Address = + // "http://localhost:5000/public/1kb.txt"; + "https://localhost:9090/public/1kb.txt"; + + public static void Main(string[] args) + { + WebRequestHandler handler = new WebRequestHandler(); + handler.ServerCertificateValidationCallback = (_, __, ___, ____) => true; + // handler.UseDefaultCredentials = true; + handler.Credentials = new NetworkCredential(@"redmond\chrross", "passwird"); + HttpClient client = new HttpClient(handler); + + /* + int completionCount = 0; + int itterations = 30000; + for (int i = 0; i < itterations; i++) + { + client.GetAsync(Address) + .ContinueWith(t => Interlocked.Increment(ref completionCount)); + } + + while (completionCount < itterations) + { + Thread.Sleep(10); + }*/ + + while (true) + { + Console.WriteLine("Press any key to send request"); + Console.ReadKey(); + var result = client.GetAsync(Address).Result; + Console.WriteLine(result); + } + + // RunWebSocketClient().Wait(); + Console.WriteLine("Done"); + Console.ReadKey(); + } + + public static async Task RunWebSocketClient() + { + ClientWebSocket websocket = new ClientWebSocket(); + + string url = "ws://localhost:5000/"; + Console.WriteLine("Connecting to: " + url); + await websocket.ConnectAsync(new Uri(url), CancellationToken.None); + + string message = "Hello World"; + Console.WriteLine("Sending message: " + message); + byte[] messageBytes = Encoding.UTF8.GetBytes(message); + await websocket.SendAsync(new ArraySegment(messageBytes), WebSocketMessageType.Text, true, CancellationToken.None); + + byte[] incomingData = new byte[1024]; + WebSocketReceiveResult result = await websocket.ReceiveAsync(new ArraySegment(incomingData), CancellationToken.None); + + if (result.CloseStatus.HasValue) + { + Console.WriteLine("Closed; Status: " + result.CloseStatus + ", " + result.CloseStatusDescription); + } + else + { + Console.WriteLine("Received message: " + Encoding.UTF8.GetString(incomingData, 0, result.Count)); + } + } + } +} diff --git a/samples/TestClient/Properties/AssemblyInfo.cs b/samples/TestClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..6919b6d3ce --- /dev/null +++ b/samples/TestClient/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestClient")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8db62eb3-48c0-4049-b33e-271c738140a0")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("0.5")] +[assembly: AssemblyVersion("0.5")] +[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/samples/TestClient/TestClient.csproj b/samples/TestClient/TestClient.csproj new file mode 100644 index 0000000000..eb38a21555 --- /dev/null +++ b/samples/TestClient/TestClient.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {8B828433-B333-4C19-96AE-00BFFF9D8841} + Exe + Properties + TestClient + TestClient + v4.5 + 512 + ..\..\ + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs b/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs new file mode 100644 index 0000000000..90a063b5fa --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs @@ -0,0 +1,37 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; + +namespace Microsoft.AspNet.Security.Windows +{ + /// + /// Types of Windows Authentication supported. + /// + [Flags] + public enum AuthTypes + { + /// + /// Default + /// + None = 0, + + /// + /// Digest authentication using Windows credentials + /// + Digest = 1, + + /// + /// Negotiates Kerberos or NTLM + /// + Negotiate = 2, + + /// + /// NTLM Windows authentication + /// + Ntlm = 4, + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs b/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs new file mode 100644 index 0000000000..ca5902dbd6 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Diagnostics; +using System.Runtime.Versioning; +using System.Security.Permissions; + +namespace Microsoft.AspNet.Security.Windows +{ + internal static class ComNetOS + { + // Minimum support for Windows 2008 is assumed. + internal static readonly bool IsWin7orLater; // Is Windows 7 or later + internal static readonly bool IsWin8orLater; // Is Windows 8 or later + + // We use it safe so assert + [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)] + [ResourceExposure(ResourceScope.None)] + [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)] + static ComNetOS() + { + OperatingSystem operatingSystem = Environment.OSVersion; + + GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString()); + + Debug.Assert(operatingSystem.Platform != PlatformID.Win32Windows, "Windows 9x is not supported"); + + var Win7Version = new Version(6, 1); + var Win8Version = new Version(6, 2); + IsWin7orLater = (operatingSystem.Version >= Win7Version); + IsWin8orLater = (operatingSystem.Version >= Win8Version); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/Constants.cs b/src/Microsoft.AspNet.Security.Windows/Constants.cs new file mode 100644 index 0000000000..28e47e83fc --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Constants.cs @@ -0,0 +1,44 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Security.Windows +{ + internal static class Constants + { + internal const string VersionKey = "owin.Version"; + internal const string OwinVersion = "1.0"; + internal const string CallCancelledKey = "owin.CallCancelled"; + + internal const string RequestBodyKey = "owin.RequestBody"; + internal const string RequestHeadersKey = "owin.RequestHeaders"; + internal const string RequestSchemeKey = "owin.RequestScheme"; + internal const string RequestMethodKey = "owin.RequestMethod"; + internal const string RequestPathBaseKey = "owin.RequestPathBase"; + internal const string RequestPathKey = "owin.RequestPath"; + internal const string RequestQueryStringKey = "owin.RequestQueryString"; + internal const string HttpRequestProtocolKey = "owin.RequestProtocol"; + + internal const string HttpResponseProtocolKey = "owin.ResponseProtocol"; + internal const string ResponseStatusCodeKey = "owin.ResponseStatusCode"; + internal const string ResponseReasonPhraseKey = "owin.ResponseReasonPhrase"; + internal const string ResponseHeadersKey = "owin.ResponseHeaders"; + internal const string ResponseBodyKey = "owin.ResponseBody"; + + internal const string ClientCertifiateKey = "ssl.ClientCertificate"; + internal const string SslSpnKey = "ssl.Spn"; + internal const string SslChannelBindingKey = "ssl.ChannelBinding"; + + internal const string RemoteIpAddressKey = "server.RemoteIpAddress"; + internal const string RemotePortKey = "server.RemotePort"; + internal const string LocalIpAddressKey = "server.LocalIpAddress"; + internal const string LocalPortKey = "server.LocalPort"; + internal const string IsLocalKey = "server.IsLocal"; + internal const string ServerOnSendingHeadersKey = "server.OnSendingHeaders"; + internal const string ServerUserKey = "server.User"; + internal const string ServerConnectionIdKey = "server.ConnectionId"; + internal const string ServerConnectionDisconnectKey = "server.ConnectionDisconnect"; + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs b/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs new file mode 100644 index 0000000000..2d1b86ad04 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs @@ -0,0 +1,67 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Linq; +using System.Text; + +namespace System.Collections.Generic +{ + internal static class DictionaryExtensions + { + internal static void Append(this IDictionary dictionary, string key, string value) + { + string[] orriginalValues; + if (dictionary.TryGetValue(key, out orriginalValues)) + { + string[] newValues = new string[orriginalValues.Length + 1]; + orriginalValues.CopyTo(newValues, 0); + newValues[newValues.Length - 1] = value; + dictionary[key] = newValues; + } + else + { + dictionary[key] = new string[] { value }; + } + } + + internal static void Append(this IDictionary dictionary, string key, IList values) + { + string[] orriginalValues; + if (dictionary.TryGetValue(key, out orriginalValues)) + { + string[] newValues = new string[orriginalValues.Length + values.Count]; + orriginalValues.CopyTo(newValues, 0); + values.CopyTo(newValues, orriginalValues.Length); + dictionary[key] = newValues; + } + else + { + dictionary[key] = values.ToArray(); + } + } + + internal static string Get(this IDictionary dictionary, string key) + { + string[] values; + if (dictionary.TryGetValue(key, out values)) + { + return string.Join(", ", values); + } + return null; + } + + internal static T Get(this IDictionary dictionary, string key, T fallback = default(T)) + { + object values; + if (dictionary.TryGetValue(key, out values)) + { + return (T)values; + } + return fallback; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/DigestCache.cs b/src/Microsoft.AspNet.Security.Windows/DigestCache.cs new file mode 100644 index 0000000000..0de3d84475 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/DigestCache.cs @@ -0,0 +1,153 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Threading; + +namespace Microsoft.AspNet.Security.Windows +{ + // Saves generated digest challenges so that they are still valid when the authenticated request arrives. + internal class DigestCache : IDisposable + { + private const int DigestLifetimeSeconds = 300; + private const int MaximumDigests = 1024; // Must be a power of two. + private const int MinimumDigestLifetimeSeconds = 10; + + private DigestContext[] _savedDigests; + private ArrayList _extraSavedDigests; + private ArrayList _extraSavedDigestsBaking; + private int _extraSavedDigestsTimestamp; + private int _newestContext; + private int _oldestContext; + + internal DigestCache() + { + } + + internal void SaveDigestContext(NTAuthentication digestContext) + { + if (_savedDigests == null) + { + Interlocked.CompareExchange(ref _savedDigests, new DigestContext[MaximumDigests], null); + } + + // We want to actually close the contexts outside the lock. + NTAuthentication oldContext = null; + ArrayList digestsToClose = null; + lock (_savedDigests) + { + int now = ((now = Environment.TickCount) == 0 ? 1 : now); + + _newestContext = (_newestContext + 1) & (MaximumDigests - 1); + + int oldTimestamp = _savedDigests[_newestContext].timestamp; + oldContext = _savedDigests[_newestContext].context; + _savedDigests[_newestContext].timestamp = now; + _savedDigests[_newestContext].context = digestContext; + + // May need to move this up. + if (_oldestContext == _newestContext) + { + _oldestContext = (_newestContext + 1) & (MaximumDigests - 1); + } + + // Delete additional contexts older than five minutes. + while (unchecked(now - _savedDigests[_oldestContext].timestamp) >= DigestLifetimeSeconds && _savedDigests[_oldestContext].context != null) + { + if (digestsToClose == null) + { + digestsToClose = new ArrayList(); + } + digestsToClose.Add(_savedDigests[_oldestContext].context); + _savedDigests[_oldestContext].context = null; + _oldestContext = (_oldestContext + 1) & (MaximumDigests - 1); + } + + // If the old context is younger than 10 seconds, put it in the backup pile. + if (oldContext != null && unchecked(now - oldTimestamp) <= MinimumDigestLifetimeSeconds * 1000) + { + // Use a two-tier ArrayList system to guarantee each entry lives at least 10 seconds. + if (_extraSavedDigests == null || + unchecked(now - _extraSavedDigestsTimestamp) > MinimumDigestLifetimeSeconds * 1000) + { + digestsToClose = _extraSavedDigestsBaking; + _extraSavedDigestsBaking = _extraSavedDigests; + _extraSavedDigestsTimestamp = now; + _extraSavedDigests = new ArrayList(); + } + _extraSavedDigests.Add(oldContext); + oldContext = null; + } + } + + if (oldContext != null) + { + oldContext.CloseContext(); + } + if (digestsToClose != null) + { + for (int i = 0; i < digestsToClose.Count; i++) + { + ((NTAuthentication)digestsToClose[i]).CloseContext(); + } + } + } + + private void ClearDigestCache() + { + if (_savedDigests == null) + { + return; + } + + ArrayList[] toClose = new ArrayList[3]; + lock (_savedDigests) + { + toClose[0] = _extraSavedDigestsBaking; + _extraSavedDigestsBaking = null; + toClose[1] = _extraSavedDigests; + _extraSavedDigests = null; + + _newestContext = 0; + _oldestContext = 0; + + toClose[2] = new ArrayList(); + for (int i = 0; i < MaximumDigests; i++) + { + if (_savedDigests[i].context != null) + { + toClose[2].Add(_savedDigests[i].context); + _savedDigests[i].context = null; + } + _savedDigests[i].timestamp = 0; + } + } + + for (int j = 0; j < toClose.Length; j++) + { + if (toClose[j] != null) + { + for (int k = 0; k < toClose[j].Count; k++) + { + ((NTAuthentication)toClose[j][k]).CloseContext(); + } + } + } + } + + public void Dispose() + { + ClearDigestCache(); + } + + private struct DigestContext + { + internal NTAuthentication context; + internal int timestamp; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs b/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs new file mode 100644 index 0000000000..6064872060 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs @@ -0,0 +1,93 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Security.Principal; +using System.Threading; + +namespace Microsoft.AspNet.Security.Windows +{ + // Keeps NTLM/Negotiate auth contexts alive until the connection is broken. + internal class DisconnectAsyncResult + { + private const string NTLM = "NTLM"; + + private object _connectionId; + private WindowsAuthMiddleware _winAuth; + private CancellationTokenRegistration _disconnectRegistration; + + private WindowsPrincipal _authenticatedUser; + private NTAuthentication _session; + + internal DisconnectAsyncResult(WindowsAuthMiddleware winAuth, object connectionId, CancellationToken connectionDisconnect) + { + GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::.ctor() httpListener#" + ValidationHelper.HashString(winAuth) + " connectionId:" + connectionId); + _winAuth = winAuth; + _connectionId = connectionId; + _winAuth.DisconnectResults[_connectionId] = this; + + // Register with a connection specific CancellationToken. Without this notification, the contexts will leak indefinitely. + // Alternatively we could attempt some kind of LRU storage, but this will either have to be larger than your expected connection limit, + // or will fail at unexpected moments under stress. + try + { + _disconnectRegistration = connectionDisconnect.Register(HandleDisconnect); + } + catch (ObjectDisposedException) + { + _winAuth.DisconnectResults.Remove(_connectionId); + } + } + + internal WindowsPrincipal AuthenticatedUser + { + get + { + return _authenticatedUser; + } + set + { + // The previous value can't be disposed because it may be in use by the app. + _authenticatedUser = value; + } + } + + internal NTAuthentication Session + { + get + { + return _session; + } + set + { + _session = value; + } + } + + private void HandleDisconnect() + { + GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::HandleDisconnect() DisconnectResults#" + ValidationHelper.HashString(_winAuth.DisconnectResults) + " removing for m_ConnectionId:" + _connectionId); + _winAuth.DisconnectResults.Remove(_connectionId); + if (_session != null) + { + _session.CloseContext(); + } + + // Clean up the identity. This is for scenarios where identity was not cleaned up before due to + // identity caching for unsafe ntlm authentication + + IDisposable identity = _authenticatedUser == null ? null : _authenticatedUser.Identity as IDisposable; + if ((identity != null) && + (NTLM.Equals(_authenticatedUser.Identity.AuthenticationType, StringComparison.OrdinalIgnoreCase)) && + (_winAuth.UnsafeConnectionNtlmAuthentication)) + { + identity.Dispose(); + } + + _disconnectRegistration.Dispose(); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs b/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs new file mode 100644 index 0000000000..7c41535d5e --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs @@ -0,0 +1,139 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Text; + +namespace Microsoft.AspNet.Security.Windows +{ + // we use this static class as a helper class to encode/decode HTTP headers. + // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF + // and a byte in the range 0x00-0xFF (which is the range that can hit the network). + // The Latin-1 encoding (ISO-88591-1) (GetEncoding(28591)) works for byte[] to string, but is a little slow. + // It doesn't work for string -> byte[] because of best-fit-mapping problems. + internal static class HeaderEncoding + { + internal static unsafe string GetString(byte[] bytes, int byteIndex, int byteCount) + { + fixed (byte* pBytes = bytes) + return GetString(pBytes + byteIndex, byteCount); + } + + internal static unsafe string GetString(byte* pBytes, int byteCount) + { + if (byteCount < 1) + { + return string.Empty; + } + + string s = new String('\0', byteCount); + + fixed (char* pStr = s) + { + char* pString = pStr; + while (byteCount >= 8) + { + pString[0] = (char)pBytes[0]; + pString[1] = (char)pBytes[1]; + pString[2] = (char)pBytes[2]; + pString[3] = (char)pBytes[3]; + pString[4] = (char)pBytes[4]; + pString[5] = (char)pBytes[5]; + pString[6] = (char)pBytes[6]; + pString[7] = (char)pBytes[7]; + pString += 8; + pBytes += 8; + byteCount -= 8; + } + for (int i = 0; i < byteCount; i++) + { + pString[i] = (char)pBytes[i]; + } + } + + return s; + } + + internal static int GetByteCount(string myString) + { + return myString.Length; + } + internal static unsafe void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex) + { + if (myString.Length == 0) + { + return; + } + fixed (byte* bufferPointer = bytes) + { + byte* newBufferPointer = bufferPointer + byteIndex; + int finalIndex = charIndex + charCount; + while (charIndex < finalIndex) + { + *newBufferPointer++ = (byte)myString[charIndex++]; + } + } + } + internal static unsafe byte[] GetBytes(string myString) + { + byte[] bytes = new byte[myString.Length]; + if (myString.Length != 0) + { + GetBytes(myString, 0, myString.Length, bytes, 0); + } + return bytes; + } + + // The normal client header parser just casts bytes to chars (see GetString). + // Check if those bytes were actually utf-8 instead of ASCII. + // If not, just return the input value. + + internal static string DecodeUtf8FromString(string input) + { + if (string.IsNullOrWhiteSpace(input)) + { + return input; + } + + bool possibleUtf8 = false; + for (int i = 0; i < input.Length; i++) + { + if (input[i] > (char)255) + { + return input; // This couldn't have come from the wire, someone assigned it directly. + } + else if (input[i] > (char)127) + { + possibleUtf8 = true; + break; + } + } + if (possibleUtf8) + { + byte[] rawBytes = new byte[input.Length]; + for (int i = 0; i < input.Length; i++) + { + if (input[i] > (char)255) + { + return input; // This couldn't have come from the wire, someone assigned it directly. + } + rawBytes[i] = (byte)input[i]; + } + try + { + // We don't want '?' replacement characters, just fail. + Encoding decoder = Encoding.GetEncoding("utf-8", EncoderFallback.ExceptionFallback, + DecoderFallback.ExceptionFallback); + return decoder.GetString(rawBytes); + } + catch (ArgumentException) + { + } // Not actually Utf-8 + } + return input; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs b/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs new file mode 100644 index 0000000000..29ab395d03 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs @@ -0,0 +1,75 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Security.Windows +{ + internal static class HttpKnownHeaderNames + { + public const string CacheControl = "Cache-Control"; + public const string Connection = "Connection"; + public const string Date = "Date"; + public const string KeepAlive = "Keep-Alive"; + public const string Pragma = "Pragma"; + public const string ProxyConnection = "Proxy-Connection"; + public const string Trailer = "Trailer"; + public const string TransferEncoding = "Transfer-Encoding"; + public const string Upgrade = "Upgrade"; + public const string Via = "Via"; + public const string Warning = "Warning"; + public const string ContentLength = "Content-Length"; + public const string ContentType = "Content-Type"; + public const string ContentDisposition = "Content-Disposition"; + public const string ContentEncoding = "Content-Encoding"; + public const string ContentLanguage = "Content-Language"; + public const string ContentLocation = "Content-Location"; + public const string ContentRange = "Content-Range"; + public const string Expires = "Expires"; + public const string LastModified = "Last-Modified"; + public const string Age = "Age"; + public const string Location = "Location"; + public const string ProxyAuthenticate = "Proxy-Authenticate"; + public const string RetryAfter = "Retry-After"; + public const string Server = "Server"; + public const string SetCookie = "Set-Cookie"; + public const string SetCookie2 = "Set-Cookie2"; + public const string Vary = "Vary"; + public const string WWWAuthenticate = "WWW-Authenticate"; + public const string Accept = "Accept"; + public const string AcceptCharset = "Accept-Charset"; + public const string AcceptEncoding = "Accept-Encoding"; + public const string AcceptLanguage = "Accept-Language"; + public const string Authorization = "Authorization"; + public const string Cookie = "Cookie"; + public const string Cookie2 = "Cookie2"; + public const string Expect = "Expect"; + public const string From = "From"; + public const string Host = "Host"; + public const string IfMatch = "If-Match"; + public const string IfModifiedSince = "If-Modified-Since"; + public const string IfNoneMatch = "If-None-Match"; + public const string IfRange = "If-Range"; + public const string IfUnmodifiedSince = "If-Unmodified-Since"; + public const string MaxForwards = "Max-Forwards"; + public const string ProxyAuthorization = "Proxy-Authorization"; + public const string Referer = "Referer"; + public const string Range = "Range"; + public const string UserAgent = "User-Agent"; + public const string ContentMD5 = "Content-MD5"; + public const string ETag = "ETag"; + public const string TE = "TE"; + public const string Allow = "Allow"; + public const string AcceptRanges = "Accept-Ranges"; + public const string P3P = "P3P"; + public const string XPoweredBy = "X-Powered-By"; + public const string XAspNetVersion = "X-AspNet-Version"; + public const string SecWebSocketKey = "Sec-WebSocket-Key"; + public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions"; + public const string SecWebSocketAccept = "Sec-WebSocket-Accept"; + public const string Origin = "Origin"; + public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol"; + public const string SecWebSocketVersion = "Sec-WebSocket-Version"; + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs b/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs new file mode 100644 index 0000000000..d60d640f2d --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs @@ -0,0 +1,314 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.Security.Windows +{ + // Redirect Status code numbers that need to be defined. + + /// + /// Contains the values of status + /// codes defined for the HTTP protocol. + /// + // UEUE : Any int can be cast to a HttpStatusCode to allow checking for non http1.1 codes. + internal enum HttpStatusCode + { + // Informational 1xx + + /// + /// [To be supplied.] + /// + Continue = 100, + + /// + /// [To be supplied.] + /// + SwitchingProtocols = 101, + + // Successful 2xx + + /// + /// [To be supplied.] + /// + OK = 200, + + /// + /// [To be supplied.] + /// + Created = 201, + + /// + /// [To be supplied.] + /// + Accepted = 202, + + /// + /// [To be supplied.] + /// + NonAuthoritativeInformation = 203, + + /// + /// [To be supplied.] + /// + NoContent = 204, + + /// + /// [To be supplied.] + /// + ResetContent = 205, + + /// + /// [To be supplied.] + /// + PartialContent = 206, + + // Redirection 3xx + + /// + /// [To be supplied.] + /// + MultipleChoices = 300, + + /// + /// [To be supplied.] + /// + Ambiguous = 300, + + /// + /// [To be supplied.] + /// + MovedPermanently = 301, + + /// + /// [To be supplied.] + /// + Moved = 301, + + /// + /// [To be supplied.] + /// + Found = 302, + + /// + /// [To be supplied.] + /// + Redirect = 302, + + /// + /// [To be supplied.] + /// + SeeOther = 303, + + /// + /// [To be supplied.] + /// + RedirectMethod = 303, + + /// + /// [To be supplied.] + /// + NotModified = 304, + + /// + /// [To be supplied.] + /// + UseProxy = 305, + + /// + /// [To be supplied.] + /// + Unused = 306, + + /// + /// [To be supplied.] + /// + TemporaryRedirect = 307, + + /// + /// [To be supplied.] + /// + RedirectKeepVerb = 307, + + // Client Error 4xx + + /// + /// [To be supplied.] + /// + BadRequest = 400, + + /// + /// [To be supplied.] + /// + Unauthorized = 401, + + /// + /// [To be supplied.] + /// + PaymentRequired = 402, + + /// + /// [To be supplied.] + /// + Forbidden = 403, + + /// + /// [To be supplied.] + /// + NotFound = 404, + + /// + /// [To be supplied.] + /// + MethodNotAllowed = 405, + + /// + /// [To be supplied.] + /// + NotAcceptable = 406, + + /// + /// [To be supplied.] + /// + ProxyAuthenticationRequired = 407, + + /// + /// [To be supplied.] + /// + RequestTimeout = 408, + + /// + /// [To be supplied.] + /// + Conflict = 409, + + /// + /// [To be supplied.] + /// + Gone = 410, + + /// + /// [To be supplied.] + /// + LengthRequired = 411, + + /// + /// [To be supplied.] + /// + PreconditionFailed = 412, + + /// + /// [To be supplied.] + /// + RequestEntityTooLarge = 413, + + /// + /// [To be supplied.] + /// + RequestUriTooLong = 414, + + /// + /// [To be supplied.] + /// + UnsupportedMediaType = 415, + + /// + /// [To be supplied.] + /// + RequestedRangeNotSatisfiable = 416, + + /// + /// [To be supplied.] + /// + ExpectationFailed = 417, + + UpgradeRequired = 426, + + // Server Error 5xx + + /// + /// [To be supplied.] + /// + InternalServerError = 500, + + /// + /// [To be supplied.] + /// + NotImplemented = 501, + + /// + /// [To be supplied.] + /// + BadGateway = 502, + + /// + /// [To be supplied.] + /// + ServiceUnavailable = 503, + + /// + /// [To be supplied.] + /// + GatewayTimeout = 504, + + /// + /// [To be supplied.] + /// + HttpVersionNotSupported = 505, + } // enum HttpStatusCode + +/* +Fielding, et al. Standards Track [Page 3] + +RFC 2616 HTTP/1.1 June 1999 + + + 10.1 Informational 1xx ...........................................57 + 10.1.1 100 Continue .............................................58 + 10.1.2 101 Switching Protocols ..................................58 + 10.2 Successful 2xx ..............................................58 + 10.2.1 200 OK ...................................................58 + 10.2.2 201 Created ..............................................59 + 10.2.3 202 Accepted .............................................59 + 10.2.4 203 Non-Authoritative Information ........................59 + 10.2.5 204 No Content ...........................................60 + 10.2.6 205 Reset Content ........................................60 + 10.2.7 206 Partial Content ......................................60 + 10.3 Redirection 3xx .............................................61 + 10.3.1 300 Multiple Choices .....................................61 + 10.3.2 301 Moved Permanently ....................................62 + 10.3.3 302 Found ................................................62 + 10.3.4 303 See Other ............................................63 + 10.3.5 304 Not Modified .........................................63 + 10.3.6 305 Use Proxy ............................................64 + 10.3.7 306 (Unused) .............................................64 + 10.3.8 307 Temporary Redirect ...................................65 + 10.4 Client Error 4xx ............................................65 + 10.4.1 400 Bad Request .........................................65 + 10.4.2 401 Unauthorized ........................................66 + 10.4.3 402 Payment Required ....................................66 + 10.4.4 403 Forbidden ...........................................66 + 10.4.5 404 Not Found ...........................................66 + 10.4.6 405 Method Not Allowed ..................................66 + 10.4.7 406 Not Acceptable ......................................67 + 10.4.8 407 Proxy Authentication Required .......................67 + 10.4.9 408 Request Timeout .....................................67 + 10.4.10 409 Conflict ............................................67 + 10.4.11 410 Gone ................................................68 + 10.4.12 411 Length Required .....................................68 + 10.4.13 412 Precondition Failed .................................68 + 10.4.14 413 Request Entity Too Large ............................69 + 10.4.15 414 Request-URI Too Long ................................69 + 10.4.16 415 Unsupported Media Type ..............................69 + 10.4.17 416 Requested Range Not Satisfiable .....................69 + 10.4.18 417 Expectation Failed ..................................70 + 10.5 Server Error 5xx ............................................70 + 10.5.1 500 Internal Server Error ................................70 + 10.5.2 501 Not Implemented ......................................70 + 10.5.3 502 Bad Gateway ..........................................70 + 10.5.4 503 Service Unavailable ..................................70 + 10.5.5 504 Gateway Timeout ......................................71 + 10.5.6 505 HTTP Version Not Supported ...........................71 +*/ +} // namespace System.Net diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs new file mode 100644 index 0000000000..8818694ff8 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs @@ -0,0 +1,133 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Collections; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class CaseInsensitiveAscii : IEqualityComparer, IComparer + { + // ASCII char ToLower table + internal static readonly byte[] AsciiToLower = new byte[] + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, // 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, // 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, // 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255 + }; + + // ASCII string case insensitive hash function + public int GetHashCode(object myObject) + { + string myString = myObject as string; + if (myObject == null) + { + return 0; + } + int myHashCode = myString.Length; + if (myHashCode == 0) + { + return 0; + } + myHashCode ^= AsciiToLower[(byte)myString[0]] << 24 ^ AsciiToLower[(byte)myString[myHashCode - 1]] << 16; + return myHashCode; + } + + // ASCII string case insensitive comparer + public int Compare(object firstObject, object secondObject) + { + string firstString = firstObject as string; + string secondString = secondObject as string; + if (firstString == null) + { + return secondString == null ? 0 : -1; + } + if (secondString == null) + { + return 1; + } + int result = firstString.Length - secondString.Length; + int comparisons = result > 0 ? secondString.Length : firstString.Length; + int difference, index = 0; + while (index < comparisons) + { + difference = (int)(AsciiToLower[firstString[index]] - AsciiToLower[secondString[index]]); + if (difference != 0) + { + result = difference; + break; + } + index++; + } + return result; + } + + // ASCII string case insensitive hash function + private int FastGetHashCode(string myString) + { + int myHashCode = myString.Length; + if (myHashCode != 0) + { + myHashCode ^= AsciiToLower[(byte)myString[0]] << 24 ^ AsciiToLower[(byte)myString[myHashCode - 1]] << 16; + } + return myHashCode; + } + + // ASCII string case insensitive comparer + public new bool Equals(object firstObject, object secondObject) + { + string firstString = firstObject as string; + string secondString = secondObject as string; + if (firstString == null) + { + return secondString == null; + } + if (secondString != null) + { + int index = firstString.Length; + if (index == secondString.Length) + { + if (FastGetHashCode(firstString) == FastGetHashCode(secondString)) + { + int comparisons = firstString.Length; + while (index > 0) + { + index--; + if (AsciiToLower[firstString[index]] != AsciiToLower[secondString[index]]) + { + return false; + } + } + return true; + } + } + } + return false; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs new file mode 100644 index 0000000000..259dc13382 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs @@ -0,0 +1,689 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Security.Windows +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Configuration; + using System.Diagnostics; + using System.Globalization; + using System.Net; + using System.Runtime.ConstrainedExecution; + using System.Security.Permissions; + using System.Threading; + + /// + /// + /// + internal static class GlobalLog + { + // Logging Initalization - I need to disable Logging code, and limit + // the effect it has when it is dissabled, so I use a bool here. + // + // This can only be set when the logging code is built and enabled. + // By specifing the "CSC_DEFINES=/D:TRAVE" in the build environment, + // this code will be built and then checks against an enviroment variable + // and a BooleanSwitch to see if any of the two have enabled logging. + + private static BaseLoggingObject Logobject = GlobalLog.LoggingInitialize(); +#if TRAVE + internal static LocalDataStoreSlot s_ThreadIdSlot; + internal static bool s_UseThreadId; + internal static bool s_UseTimeSpan; + internal static bool s_DumpWebData; + internal static bool s_UsePerfCounter; + internal static bool s_DebugCallNesting; + internal static bool s_DumpToConsole; + internal static int s_MaxDumpSize; + internal static string s_RootDirectory; + + // + // Logging Config Variables - below are list of consts that can be used to config + // the logging, + // + + // Max number of lines written into a buffer, before a save is invoked + // s_DumpToConsole disables. + public const int MaxLinesBeforeSave = 0; + +#endif + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + private static BaseLoggingObject LoggingInitialize() + { +#if DEBUG + if (GetSwitchValue("SystemNetLogging", "System.Net logging module", false) && + GetSwitchValue("SystemNetLog_ConnectionMonitor", "System.Net connection monitor thread", false)) + { + InitConnectionMonitor(); + } +#endif // DEBUG +#if TRAVE + // by default we'll log to c:\temp\ so that non interactive services (like w3wp.exe) that don't have environment + // variables can easily be debugged, note that the ACLs of the directory might need to be adjusted + if (!GetSwitchValue("SystemNetLog_OverrideDefaults", "System.Net log override default settings", false)) { + s_ThreadIdSlot = Thread.AllocateDataSlot(); + s_UseThreadId = true; + s_UseTimeSpan = true; + s_DumpWebData = true; + s_MaxDumpSize = 256; + s_UsePerfCounter = true; + s_DebugCallNesting = true; + s_DumpToConsole = false; + s_RootDirectory = "C:\\Temp\\"; + return new LoggingObject(); + } + if (GetSwitchValue("SystemNetLogging", "System.Net logging module", false)) { + s_ThreadIdSlot = Thread.AllocateDataSlot(); + s_UseThreadId = GetSwitchValue("SystemNetLog_UseThreadId", "System.Net log display system thread id", false); + s_UseTimeSpan = GetSwitchValue("SystemNetLog_UseTimeSpan", "System.Net log display ticks as TimeSpan", false); + s_DumpWebData = GetSwitchValue("SystemNetLog_DumpWebData", "System.Net log display HTTP send/receive data", false); + s_MaxDumpSize = GetSwitchValue("SystemNetLog_MaxDumpSize", "System.Net log max size of display data", 256); + s_UsePerfCounter = GetSwitchValue("SystemNetLog_UsePerfCounter", "System.Net log use QueryPerformanceCounter() to get ticks ", false); + s_DebugCallNesting = GetSwitchValue("SystemNetLog_DebugCallNesting", "System.Net used to debug call nesting", false); + s_DumpToConsole = GetSwitchValue("SystemNetLog_DumpToConsole", "System.Net log to console", false); + s_RootDirectory = GetSwitchValue("SystemNetLog_RootDirectory", "System.Net root directory of log file", string.Empty); + return new LoggingObject(); + } +#endif // TRAVE + return new BaseLoggingObject(); + } + +#if TRAVE + private static string GetSwitchValue(string switchName, string switchDescription, string defaultValue) { + new EnvironmentPermission(PermissionState.Unrestricted).Assert(); + try { + defaultValue = Environment.GetEnvironmentVariable(switchName); + } + finally { + EnvironmentPermission.RevertAssert(); + } + return defaultValue; + } + + private static int GetSwitchValue(string switchName, string switchDescription, int defaultValue) { + IntegerSwitch theSwitch = new IntegerSwitch(switchName, switchDescription); + if (theSwitch.Enabled) { + return theSwitch.Value; + } + new EnvironmentPermission(PermissionState.Unrestricted).Assert(); + try { + string environmentVar = Environment.GetEnvironmentVariable(switchName); + if (environmentVar!=null) { + defaultValue = Int32.Parse(environmentVar.Trim(), CultureInfo.InvariantCulture); + } + } + finally { + EnvironmentPermission.RevertAssert(); + } + return defaultValue; + } + +#endif + +#if TRAVE || DEBUG + private static bool GetSwitchValue(string switchName, string switchDescription, bool defaultValue) + { + BooleanSwitch theSwitch = new BooleanSwitch(switchName, switchDescription); + new EnvironmentPermission(PermissionState.Unrestricted).Assert(); + try + { + if (theSwitch.Enabled) + { + return true; + } + string environmentVar = Environment.GetEnvironmentVariable(switchName); + defaultValue = environmentVar != null && environmentVar.Trim() == "1"; + } + catch (ConfigurationException) + { + } + finally + { + EnvironmentPermission.RevertAssert(); + } + return defaultValue; + } +#endif // TRAVE || DEBUG + + // Enables thread tracing, detects mis-use of threads. +#if DEBUG + [ThreadStatic] + private static Stack t_ThreadKindStack; + + private static Stack ThreadKindStack + { + get + { + if (t_ThreadKindStack == null) + { + t_ThreadKindStack = new Stack(); + } + return t_ThreadKindStack; + } + } +#endif + + internal static ThreadKinds CurrentThreadKind + { + get + { +#if DEBUG + return ThreadKindStack.Count > 0 ? ThreadKindStack.Peek() : ThreadKinds.Other; +#else + return ThreadKinds.Unknown; +#endif + } + } + + private static bool HasShutdownStarted + { + get + { + return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload(); + } + } + +#if DEBUG + // ifdef'd instead of conditional since people are forced to handle the return value. + // [Conditional("DEBUG")] + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + internal static IDisposable SetThreadKind(ThreadKinds kind) + { + if ((kind & ThreadKinds.SourceMask) != ThreadKinds.Unknown) + { + throw new InvalidOperationException(); + } + + // Ignore during shutdown. + if (HasShutdownStarted) + { + return null; + } + + ThreadKinds threadKind = CurrentThreadKind; + ThreadKinds source = threadKind & ThreadKinds.SourceMask; + +#if TRAVE + // Special warnings when doing dangerous things on a thread. + if ((threadKind & ThreadKinds.User) != 0 && (kind & ThreadKinds.System) != 0) + { + Print("WARNING: Thread changed from User to System; user's thread shouldn't be hijacked."); + } + + if ((threadKind & ThreadKinds.Async) != 0 && (kind & ThreadKinds.Sync) != 0) + { + Print("WARNING: Thread changed from Async to Sync, may block an Async thread."); + } + else if ((threadKind & (ThreadKinds.Other | ThreadKinds.CompletionPort)) == 0 && (kind & ThreadKinds.Sync) != 0) + { + Print("WARNING: Thread from a limited resource changed to Sync, may deadlock or bottleneck."); + } +#endif + + ThreadKindStack.Push( + (((kind & ThreadKinds.OwnerMask) == 0 ? threadKind : kind) & ThreadKinds.OwnerMask) | + (((kind & ThreadKinds.SyncMask) == 0 ? threadKind : kind) & ThreadKinds.SyncMask) | + (kind & ~(ThreadKinds.OwnerMask | ThreadKinds.SyncMask)) | + source); + +#if TRAVE + if (CurrentThreadKind != threadKind) + { + Print("Thread becomes:(" + CurrentThreadKind.ToString() + ")"); + } +#endif + + return new ThreadKindFrame(); + } + + private class ThreadKindFrame : IDisposable + { + private int m_FrameNumber; + + internal ThreadKindFrame() + { + m_FrameNumber = ThreadKindStack.Count; + } + + void IDisposable.Dispose() + { + // Ignore during shutdown. + if (GlobalLog.HasShutdownStarted) + { + return; + } + + if (m_FrameNumber != ThreadKindStack.Count) + { + throw new InvalidOperationException(); + } + + ThreadKinds previous = ThreadKindStack.Pop(); + +#if TRAVE + if (CurrentThreadKind != previous) + { + Print("Thread reverts:(" + CurrentThreadKind.ToString() + ")"); + } +#endif + } + } +#endif + + [Conditional("DEBUG")] + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + internal static void SetThreadSource(ThreadKinds source) + { +#if DEBUG + if ((source & ThreadKinds.SourceMask) != source || source == ThreadKinds.Unknown) + { + throw new ArgumentException("Must specify the thread source.", "source"); + } + + if (ThreadKindStack.Count == 0) + { + ThreadKindStack.Push(source); + return; + } + + if (ThreadKindStack.Count > 1) + { + Print("WARNING: SetThreadSource must be called at the base of the stack, or the stack has been corrupted."); + while (ThreadKindStack.Count > 1) + { + ThreadKindStack.Pop(); + } + } + + if (ThreadKindStack.Peek() != source) + { + // SQL can fail to clean up the stack, leaving the default Other at the bottom. Replace it. + Print("WARNING: The stack has been corrupted."); + ThreadKinds last = ThreadKindStack.Pop() & ThreadKinds.SourceMask; + Assert(last == source || last == ThreadKinds.Other, "Thread source changed.|Was:({0}) Now:({1})", last, source); + ThreadKindStack.Push(source); + } +#endif + } + + [Conditional("DEBUG")] + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + internal static void ThreadContract(ThreadKinds kind, string errorMsg) + { + ThreadContract(kind, ThreadKinds.SafeSources, errorMsg); + } + + [Conditional("DEBUG")] + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + internal static void ThreadContract(ThreadKinds kind, ThreadKinds allowedSources, string errorMsg) + { + if ((kind & ThreadKinds.SourceMask) != ThreadKinds.Unknown || (allowedSources & ThreadKinds.SourceMask) != allowedSources) + { + throw new InvalidOperationException(); + } + + ThreadKinds threadKind = CurrentThreadKind; + Assert((threadKind & allowedSources) != 0, errorMsg, "Thread Contract Violation.|Expected source:({0}) Actual source:({1})", allowedSources, threadKind & ThreadKinds.SourceMask); + Assert((threadKind & kind) == kind, errorMsg, "Thread Contract Violation.|Expected kind:({0}) Actual kind:({1})", kind, threadKind & ~ThreadKinds.SourceMask); + } + +#if DEBUG + // Enables auto-hang detection, which will "snap" a log on hang + internal static bool EnableMonitorThread = false; + + // Default value for hang timer +#if FEATURE_PAL // ROTORTODO - after speedups (like real JIT and GC) remove this + public const int DefaultTickValue = 1000*60*5; // 5 minutes +#else + public const int DefaultTickValue = 1000 * 60; // 60 secs +#endif // FEATURE_PAL +#endif // DEBUG + + [System.Diagnostics.Conditional("TRAVE")] + public static void AddToArray(string msg) + { +#if TRAVE + GlobalLog.Logobject.PrintLine(msg); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Ignore(object msg) + { + } + + [System.Diagnostics.Conditional("TRAVE")] + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + public static void Print(string msg) + { +#if TRAVE + GlobalLog.Logobject.PrintLine(msg); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void PrintHex(string msg, object value) + { +#if TRAVE + GlobalLog.Logobject.PrintLine(msg+TraveHelper.ToHex(value)); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Enter(string func) + { +#if TRAVE + GlobalLog.Logobject.EnterFunc(func + "(*none*)"); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Enter(string func, string parms) + { +#if TRAVE + GlobalLog.Logobject.EnterFunc(func + "(" + parms + ")"); +#endif + } + + [Conditional("DEBUG")] + [Conditional("_FORCE_ASSERTS")] + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + public static void Assert(bool condition, string messageFormat, params object[] data) + { + if (!condition) + { + string fullMessage = string.Format(CultureInfo.InvariantCulture, messageFormat, data); + int pipeIndex = fullMessage.IndexOf('|'); + if (pipeIndex == -1) + { + Assert(fullMessage); + } + else + { + int detailLength = fullMessage.Length - pipeIndex - 1; + Assert(fullMessage.Substring(0, pipeIndex), detailLength > 0 ? fullMessage.Substring(pipeIndex + 1, detailLength) : null); + } + } + } + + [Conditional("DEBUG")] + [Conditional("_FORCE_ASSERTS")] + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + public static void Assert(string message) + { + Assert(message, null); + } + + [Conditional("DEBUG")] + [Conditional("_FORCE_ASSERTS")] + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + public static void Assert(string message, string detailMessage) + { + try + { + Print("Assert: " + message + (!string.IsNullOrEmpty(detailMessage) ? ": " + detailMessage : string.Empty)); + Print("*******"); + Logobject.DumpArray(false); + } + finally + { +#if DEBUG && !STRESS + Debug.Assert(false, message, detailMessage); +#endif + } + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void LeaveException(string func, Exception exception) + { +#if TRAVE + GlobalLog.Logobject.LeaveFunc(func + " exception " + ((exception!=null) ? exception.Message : String.Empty)); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Leave(string func) + { +#if TRAVE + GlobalLog.Logobject.LeaveFunc(func + " returns "); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Leave(string func, string result) + { +#if TRAVE + GlobalLog.Logobject.LeaveFunc(func + " returns " + result); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Leave(string func, int returnval) + { +#if TRAVE + GlobalLog.Logobject.LeaveFunc(func + " returns " + returnval.ToString()); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Leave(string func, bool returnval) + { +#if TRAVE + GlobalLog.Logobject.LeaveFunc(func + " returns " + returnval.ToString()); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void DumpArray() + { +#if TRAVE + GlobalLog.Logobject.DumpArray(true); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Dump(byte[] buffer) + { +#if TRAVE + Logobject.Dump(buffer, 0, buffer!=null ? buffer.Length : -1); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Dump(byte[] buffer, int length) + { +#if TRAVE + Logobject.Dump(buffer, 0, length); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Dump(byte[] buffer, int offset, int length) + { +#if TRAVE + Logobject.Dump(buffer, offset, length); +#endif + } + + [System.Diagnostics.Conditional("TRAVE")] + public static void Dump(IntPtr buffer, int offset, int length) + { +#if TRAVE + Logobject.Dump(buffer, offset, length); +#endif + } + +#if DEBUG + private class HttpWebRequestComparer : IComparer + { + public int Compare( + object x1, + object y1) + { + HttpWebRequest x = (HttpWebRequest)x1; + HttpWebRequest y = (HttpWebRequest)y1; + + if (x.GetHashCode() == y.GetHashCode()) + { + return 0; + } + else if (x.GetHashCode() < y.GetHashCode()) + { + return -1; + } + else if (x.GetHashCode() > y.GetHashCode()) + { + return 1; + } + + return 0; + } + } + /* + private class ConnectionMonitorEntry { + public HttpWebRequest m_Request; + public int m_Flags; + public DateTime m_TimeAdded; + public Connection m_Connection; + + public ConnectionMonitorEntry(HttpWebRequest request, Connection connection, int flags) { + m_Request = request; + m_Connection = connection; + m_Flags = flags; + m_TimeAdded = DateTime.Now; + } + } + */ + private static volatile ManualResetEvent s_ShutdownEvent; + private static volatile SortedList s_RequestList; + + internal const int WaitingForReadDoneFlag = 0x1; +#endif + /* +#if DEBUG + private static void ConnectionMonitor() { + while(! s_ShutdownEvent.WaitOne(DefaultTickValue, false)) { + if (GlobalLog.EnableMonitorThread) { +#if TRAVE + GlobalLog.Logobject.LoggingMonitorTick(); +#endif + } + + int hungCount = 0; + lock (s_RequestList) { + DateTime dateNow = DateTime.Now; + DateTime dateExpired = dateNow.AddSeconds(-DefaultTickValue); + foreach (ConnectionMonitorEntry monitorEntry in s_RequestList.GetValueList() ) { + if (monitorEntry != null && + (dateExpired > monitorEntry.m_TimeAdded)) + { + hungCount++; +#if TRAVE + GlobalLog.Print("delay:" + (dateNow - monitorEntry.m_TimeAdded).TotalSeconds + + " req#" + monitorEntry.m_Request.GetHashCode() + + " cnt#" + monitorEntry.m_Connection.GetHashCode() + + " flags:" + monitorEntry.m_Flags); + +#endif + monitorEntry.m_Connection.Debug(monitorEntry.m_Request.GetHashCode()); + } + } + } + Assert(hungCount == 0, "Warning: Hang Detected on Connection(s) of greater than {0} ms. {1} request(s) hung.|Please Dump System.Net.GlobalLog.s_RequestList for pending requests, make sure your streams are calling Close(), and that your destination server is up.", DefaultTickValue, hungCount); + } + } +#endif // DEBUG + **/ +#if DEBUG + [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] + internal static void AppDomainUnloadEvent(object sender, EventArgs e) + { + s_ShutdownEvent.Set(); + } +#endif + +#if DEBUG + [System.Diagnostics.Conditional("DEBUG")] + private static void InitConnectionMonitor() + { + s_RequestList = new SortedList(new HttpWebRequestComparer(), 10); + s_ShutdownEvent = new ManualResetEvent(false); + AppDomain.CurrentDomain.DomainUnload += new EventHandler(AppDomainUnloadEvent); + AppDomain.CurrentDomain.ProcessExit += new EventHandler(AppDomainUnloadEvent); + // Thread threadMonitor = new Thread(new ThreadStart(ConnectionMonitor)); + // threadMonitor.IsBackground = true; + // threadMonitor.Start(); + } +#endif + /* + [System.Diagnostics.Conditional("DEBUG")] + internal static void DebugAddRequest(HttpWebRequest request, Connection connection, int flags) { +#if DEBUG + // null if the connection monitor is off + if(s_RequestList == null) + return; + + lock(s_RequestList) { + Assert(!s_RequestList.ContainsKey(request), "s_RequestList.ContainsKey(request)|A HttpWebRequest should not be submitted twice."); + + ConnectionMonitorEntry requestEntry = + new ConnectionMonitorEntry(request, connection, flags); + + try { + s_RequestList.Add(request, requestEntry); + } catch { + } + } +#endif + } +*/ + /* + [System.Diagnostics.Conditional("DEBUG")] + internal static void DebugRemoveRequest(HttpWebRequest request) { + #if DEBUG + // null if the connection monitor is off + if(s_RequestList == null) + return; + + lock(s_RequestList) { + Assert(s_RequestList.ContainsKey(request), "!s_RequestList.ContainsKey(request)|A HttpWebRequest should not be removed twice."); + + try { + s_RequestList.Remove(request); + } catch { + } + } + #endif + } + */ + /* + [System.Diagnostics.Conditional("DEBUG")] + internal static void DebugUpdateRequest(HttpWebRequest request, Connection connection, int flags) { +#if DEBUG + // null if the connection monitor is off + if(s_RequestList == null) + return; + + lock(s_RequestList) { + if(!s_RequestList.ContainsKey(request)) { + return; + } + + ConnectionMonitorEntry requestEntry = + new ConnectionMonitorEntry(request, connection, flags); + + try { + s_RequestList.Remove(request); + s_RequestList.Add(request, requestEntry); + } catch { + } + } +#endif + }*/ + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs new file mode 100644 index 0000000000..9b9335906f --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Security.Principal; + +namespace Microsoft.AspNet.Security.Windows +{ + // TODO: At what point does a user need to be cleaned up? + internal sealed class HttpListenerContext + { + private WindowsAuthMiddleware _winAuth; + private IPrincipal _user = null; + + internal const string NTLM = "NTLM"; + + internal HttpListenerContext(WindowsAuthMiddleware httpListener) + { + _winAuth = httpListener; + } + + internal void Close() + { + if (Logging.On) + { + Logging.Enter(Logging.HttpListener, this, "Close()", string.Empty); + } + + IDisposable user = _user == null ? null : _user.Identity as IDisposable; + + // TODO: At what point does a user need to be cleaned up? + + // For unsafe connection ntlm auth we dont dispose this identity as yet since its cached + if ((user != null) && + (_user.Identity.AuthenticationType != NTLM) && + (!_winAuth.UnsafeConnectionNtlmAuthentication)) + { + user.Dispose(); + } + if (Logging.On) + { + Logging.Exit(Logging.HttpListener, this, "Close", string.Empty); + } + } + + internal void Abort() + { + if (Logging.On) + { + Logging.Enter(Logging.HttpListener, this, "Abort", string.Empty); + } + + IDisposable user = _user == null ? null : _user.Identity as IDisposable; + if (user != null) + { + user.Dispose(); + } + if (Logging.On) + { + Logging.Exit(Logging.HttpListener, this, "Abort", string.Empty); + } + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs new file mode 100644 index 0000000000..4d922591dd --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs @@ -0,0 +1,286 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Net.Security; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Security.Authentication.ExtendedProtection; +using System.Security.Cryptography.X509Certificates; +using System.Security.Permissions; + +namespace Microsoft.AspNet.Security.Windows +{ + internal enum SecurityStatus + { + // Success / Informational + OK = 0x00000000, + ContinueNeeded = unchecked((int)0x00090312), + CompleteNeeded = unchecked((int)0x00090313), + CompAndContinue = unchecked((int)0x00090314), + ContextExpired = unchecked((int)0x00090317), + CredentialsNeeded = unchecked((int)0x00090320), + Renegotiate = unchecked((int)0x00090321), + + // Errors + OutOfMemory = unchecked((int)0x80090300), + InvalidHandle = unchecked((int)0x80090301), + Unsupported = unchecked((int)0x80090302), + TargetUnknown = unchecked((int)0x80090303), + InternalError = unchecked((int)0x80090304), + PackageNotFound = unchecked((int)0x80090305), + NotOwner = unchecked((int)0x80090306), + CannotInstall = unchecked((int)0x80090307), + InvalidToken = unchecked((int)0x80090308), + CannotPack = unchecked((int)0x80090309), + QopNotSupported = unchecked((int)0x8009030A), + NoImpersonation = unchecked((int)0x8009030B), + LogonDenied = unchecked((int)0x8009030C), + UnknownCredentials = unchecked((int)0x8009030D), + NoCredentials = unchecked((int)0x8009030E), + MessageAltered = unchecked((int)0x8009030F), + OutOfSequence = unchecked((int)0x80090310), + NoAuthenticatingAuthority = unchecked((int)0x80090311), + IncompleteMessage = unchecked((int)0x80090318), + IncompleteCredentials = unchecked((int)0x80090320), + BufferNotEnough = unchecked((int)0x80090321), + WrongPrincipal = unchecked((int)0x80090322), + TimeSkew = unchecked((int)0x80090324), + UntrustedRoot = unchecked((int)0x80090325), + IllegalMessage = unchecked((int)0x80090326), + CertUnknown = unchecked((int)0x80090327), + CertExpired = unchecked((int)0x80090328), + AlgorithmMismatch = unchecked((int)0x80090331), + SecurityQosFailed = unchecked((int)0x80090332), + SmartcardLogonRequired = unchecked((int)0x8009033E), + UnsupportedPreauth = unchecked((int)0x80090343), + BadBinding = unchecked((int)0x80090346) + } + + internal enum ContextAttribute + { + // look into and + Sizes = 0x00, + Names = 0x01, + Lifespan = 0x02, + DceInfo = 0x03, + StreamSizes = 0x04, + // KeyInfo = 0x05, must not be used, see ConnectionInfo instead + Authority = 0x06, + // SECPKG_ATTR_PROTO_INFO = 7, + // SECPKG_ATTR_PASSWORD_EXPIRY = 8, + // SECPKG_ATTR_SESSION_KEY = 9, + PackageInfo = 0x0A, + // SECPKG_ATTR_USER_FLAGS = 11, + NegotiationInfo = 0x0C, + // SECPKG_ATTR_NATIVE_NAMES = 13, + // SECPKG_ATTR_FLAGS = 14, + // SECPKG_ATTR_USE_VALIDATED = 15, + // SECPKG_ATTR_CREDENTIAL_NAME = 16, + // SECPKG_ATTR_TARGET_INFORMATION = 17, + // SECPKG_ATTR_ACCESS_TOKEN = 18, + // SECPKG_ATTR_TARGET = 19, + // SECPKG_ATTR_AUTHENTICATION_ID = 20, + UniqueBindings = 0x19, + EndpointBindings = 0x1A, + ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27 + RemoteCertificate = 0x53, + LocalCertificate = 0x54, + RootStore = 0x55, + IssuerListInfoEx = 0x59, + ConnectionInfo = 0x5A, + // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock + // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr + // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo + // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData + // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates + // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy + // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult + // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group + // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo + // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo + // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo + // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures + // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT + UiInfo = 0x68, // sets SEcPkgContext_UiInfo + } + + internal enum Endianness + { + Network = 0x00, + Native = 0x10, + } + + internal enum CredentialUse + { + Inbound = 0x1, + Outbound = 0x2, + Both = 0x3, + } + + internal enum BufferType + { + Empty = 0x00, + Data = 0x01, + Token = 0x02, + Parameters = 0x03, + Missing = 0x04, + Extra = 0x05, + Trailer = 0x06, + Header = 0x07, + Padding = 0x09, // non-data padding + Stream = 0x0A, + ChannelBindings = 0x0E, + TargetHost = 0x10, + ReadOnlyFlag = unchecked((int)0x80000000), + ReadOnlyWithChecksum = 0x10000000 + } + + // SecPkgContext_IssuerListInfoEx + [StructLayout(LayoutKind.Sequential)] + internal struct IssuerListInfoEx + { + public SafeHandle aIssuers; + public uint cIssuers; + + public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) + { + aIssuers = handle; + fixed (byte* voidPtr = nativeBuffer) + { + // if this breaks on 64 bit, do the sizeof(IntPtr) trick + cIssuers = *((uint*)(voidPtr + IntPtr.Size)); + } + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SecureCredential + { + /* + typedef struct _SCHANNEL_CRED + { + DWORD dwVersion; // always SCHANNEL_CRED_VERSION + DWORD cCreds; + PCCERT_CONTEXT *paCred; + HCERTSTORE hRootStore; + + DWORD cMappers; + struct _HMAPPER **aphMappers; + + DWORD cSupportedAlgs; + ALG_ID * palgSupportedAlgs; + + DWORD grbitEnabledProtocols; + DWORD dwMinimumCipherStrength; + DWORD dwMaximumCipherStrength; + DWORD dwSessionLifespan; + DWORD dwFlags; + DWORD reserved; + } SCHANNEL_CRED, *PSCHANNEL_CRED; + */ + + public const int CurrentVersion = 0x4; + + public int version; + public int cCreds; + + // ptr to an array of pointers + // There is a hack done with this field. AcquireCredentialsHandle requires an array of + // certificate handles; we only ever use one. In order to avoid pinning a one element array, + // we copy this value onto the stack, create a pointer on the stack to the copied value, + // and replace this field with the pointer, during the call to AcquireCredentialsHandle. + // Then we fix it up afterwards. Fine as long as all the SSPI credentials are not + // supposed to be threadsafe. + public IntPtr certContextArray; + + private readonly IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE + public int cMappers; + private readonly IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE + public int cSupportedAlgs; + private readonly IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE + public SchProtocols grbitEnabledProtocols; + public int dwMinimumCipherStrength; + public int dwMaximumCipherStrength; + public int dwSessionLifespan; + public SecureCredential.Flags dwFlags; + public int reserved; + + public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) + { + // default values required for a struct + rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero; + cCreds = cMappers = cSupportedAlgs = 0; + + if (policy == EncryptionPolicy.RequireEncryption) + { + // Prohibit null encryption cipher + dwMinimumCipherStrength = 0; + dwMaximumCipherStrength = 0; + } + else if (policy == EncryptionPolicy.AllowNoEncryption) + { + // Allow null encryption cipher in addition to other ciphers + dwMinimumCipherStrength = -1; + dwMaximumCipherStrength = 0; + } + else if (policy == EncryptionPolicy.NoEncryption) + { + // Suppress all encryption and require null encryption cipher only + dwMinimumCipherStrength = -1; + dwMaximumCipherStrength = -1; + } + else + { + throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy"); + } + + dwSessionLifespan = reserved = 0; + this.version = version; + dwFlags = flags; + grbitEnabledProtocols = protocols; + if (certificate != null) + { + certContextArray = certificate.Handle; + cCreds = 1; + } + } + + [Flags] + public enum Flags + { + Zero = 0, + NoSystemMapper = 0x02, + NoNameCheck = 0x04, + ValidateManual = 0x08, + NoDefaultCred = 0x10, + ValidateAuto = 0x20 + } + } // SecureCredential + + [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable", + Justification = "This structure does not own the native resource.")] + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct SecurityBufferStruct + { + public int count; + public BufferType type; + public IntPtr token; + + public static readonly int Size = sizeof(SecurityBufferStruct); + } + + internal static class IntPtrHelper + { + internal static IntPtr Add(IntPtr a, int b) + { + return (IntPtr)((long)a + (long)b); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs new file mode 100644 index 0000000000..81e66a3c30 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs @@ -0,0 +1,657 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Security; +using System.Threading; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class Logging + { + private const string AttributeNameMaxSize = "maxdatasize"; + private const string AttributeNameTraceMode = "tracemode"; + private const string AttributeValueProtocolOnly = "protocolonly"; + // private const string AttributeValueIncludeHex = "includehex"; + + private const int DefaultMaxDumpSize = 1024; + private const bool DefaultUseProtocolTextOnly = false; + + private const string TraceSourceWebName = "System.Net"; + private const string TraceSourceHttpListenerName = "System.Net.HttpListener"; + + private static readonly string[] SupportedAttributes = new string[] { AttributeNameMaxSize, AttributeNameTraceMode }; + + private static volatile bool s_LoggingEnabled = true; + private static volatile bool s_LoggingInitialized; + private static volatile bool s_AppDomainShutdown; + + private static TraceSource s_WebTraceSource; + private static TraceSource s_HttpListenerTraceSource; + + private static object s_InternalSyncObject; + + private Logging() + { + } + + private static object InternalSyncObject + { + get + { + if (s_InternalSyncObject == null) + { + object o = new Object(); + Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); + } + return s_InternalSyncObject; + } + } + + internal static bool On + { + get + { + if (!s_LoggingInitialized) + { + InitializeLogging(); + } + return s_LoggingEnabled; + } + } + + internal static bool IsVerbose(TraceSource traceSource) + { + return ValidateSettings(traceSource, TraceEventType.Verbose); + } + + internal static TraceSource Web + { + get + { + if (!s_LoggingInitialized) + { + InitializeLogging(); + } + if (!s_LoggingEnabled) + { + return null; + } + return s_WebTraceSource; + } + } + + internal static TraceSource HttpListener + { + get + { + if (!s_LoggingInitialized) + { + InitializeLogging(); + } + if (!s_LoggingEnabled) + { + return null; + } + return s_HttpListenerTraceSource; + } + } + + private static bool GetUseProtocolTextSetting(TraceSource traceSource) + { + bool useProtocolTextOnly = DefaultUseProtocolTextOnly; + if (traceSource.Attributes[AttributeNameTraceMode] == AttributeValueProtocolOnly) + { + useProtocolTextOnly = true; + } + return useProtocolTextOnly; + } + + private static int GetMaxDumpSizeSetting(TraceSource traceSource) + { + int maxDumpSize = DefaultMaxDumpSize; + if (traceSource.Attributes.ContainsKey(AttributeNameMaxSize)) + { + try + { + maxDumpSize = Int32.Parse(traceSource.Attributes[AttributeNameMaxSize], NumberFormatInfo.InvariantInfo); + } + catch (Exception exception) + { + if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) + { + throw; + } + traceSource.Attributes[AttributeNameMaxSize] = maxDumpSize.ToString(NumberFormatInfo.InvariantInfo); + } + } + return maxDumpSize; + } + + /// + /// Sets up internal config settings for logging. (MUST be called under critsec) + /// + private static void InitializeLogging() + { + lock (InternalSyncObject) + { + if (!s_LoggingInitialized) + { + bool loggingEnabled = false; + s_WebTraceSource = new NclTraceSource(TraceSourceWebName); + s_HttpListenerTraceSource = new NclTraceSource(TraceSourceHttpListenerName); + + GlobalLog.Print("Initalizating tracing"); + + try + { + loggingEnabled = (s_WebTraceSource.Switch.ShouldTrace(TraceEventType.Critical) || + s_HttpListenerTraceSource.Switch.ShouldTrace(TraceEventType.Critical)); + } + catch (SecurityException) + { + // These may throw if the caller does not have permission to hook up trace listeners. + // We treat this case as though logging were disabled. + Close(); + loggingEnabled = false; + } + if (loggingEnabled) + { + AppDomain currentDomain = AppDomain.CurrentDomain; + currentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler); + currentDomain.DomainUnload += new EventHandler(AppDomainUnloadEvent); + currentDomain.ProcessExit += new EventHandler(ProcessExitEvent); + } + s_LoggingEnabled = loggingEnabled; + s_LoggingInitialized = true; + } + } + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Logging functions must work in partial trust mode")] + private static void Close() + { + if (s_WebTraceSource != null) + { + s_WebTraceSource.Close(); + } + if (s_HttpListenerTraceSource != null) + { + s_HttpListenerTraceSource.Close(); + } + } + + /// + /// Logs any unhandled exception through this event handler + /// + private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) + { + Exception e = (Exception)args.ExceptionObject; + Exception(Web, sender, "UnhandledExceptionHandler", e); + } + + private static void ProcessExitEvent(object sender, EventArgs e) + { + Close(); + s_AppDomainShutdown = true; + } + + /// + /// Called when the system is shutting down, used to prevent additional logging post-shutdown + /// + private static void AppDomainUnloadEvent(object sender, EventArgs e) + { + Close(); + s_AppDomainShutdown = true; + } + + /// + /// Confirms logging is enabled, given current logging settings + /// + private static bool ValidateSettings(TraceSource traceSource, TraceEventType traceLevel) + { + if (!s_LoggingEnabled) + { + return false; + } + if (!s_LoggingInitialized) + { + InitializeLogging(); + } + if (traceSource == null || !traceSource.Switch.ShouldTrace(traceLevel)) + { + return false; + } + if (s_AppDomainShutdown) + { + return false; + } + return true; + } + + /// + /// Converts an object to a normalized string that can be printed + /// takes System.Net.ObjectNamedFoo and coverts to ObjectNamedFoo, + /// except IPAddress, IPEndPoint, and Uri, which return ToString() + /// + /// + private static string GetObjectName(object obj) + { + if (obj is Uri || obj is System.Net.IPAddress || obj is System.Net.IPEndPoint) + { + return obj.ToString(); + } + else + { + return obj.GetType().Name; + } + } + + internal static uint GetThreadId() + { + uint threadId = UnsafeNclNativeMethods.GetCurrentThreadId(); + if (threadId == 0) + { + threadId = (uint)Thread.CurrentThread.GetHashCode(); + } + return threadId; + } + + internal static void PrintLine(TraceSource traceSource, TraceEventType eventType, int id, string msg) + { + string logHeader = "[" + GetThreadId().ToString("d4", CultureInfo.InvariantCulture) + "] "; + traceSource.TraceEvent(eventType, id, logHeader + msg); + } + + /// + /// Indicates that two objects are getting used with one another + /// + internal static void Associate(TraceSource traceSource, object objA, object objB) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + + string lineA = GetObjectName(objA) + "#" + ValidationHelper.HashString(objA); + string lineB = GetObjectName(objB) + "#" + ValidationHelper.HashString(objB); + + PrintLine(traceSource, TraceEventType.Information, 0, "Associating " + lineA + " with " + lineB); + } + + /// + /// Logs entrance to a function + /// + internal static void Enter(TraceSource traceSource, object obj, string method, string param) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + Enter(traceSource, GetObjectName(obj) + "#" + ValidationHelper.HashString(obj), method, param); + } + + /// + /// Logs entrance to a function + /// + internal static void Enter(TraceSource traceSource, object obj, string method, object paramObject) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + Enter(traceSource, GetObjectName(obj) + "#" + ValidationHelper.HashString(obj), method, paramObject); + } + + /// + /// Logs entrance to a function + /// + internal static void Enter(TraceSource traceSource, string obj, string method, string param) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + Enter(traceSource, obj + "::" + method + "(" + param + ")"); + } + + /// + /// Logs entrance to a function + /// + internal static void Enter(TraceSource traceSource, string obj, string method, object paramObject) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + string paramObjectValue = string.Empty; + if (paramObject != null) + { + paramObjectValue = GetObjectName(paramObject) + "#" + ValidationHelper.HashString(paramObject); + } + Enter(traceSource, obj + "::" + method + "(" + paramObjectValue + ")"); + } + + /// + /// Logs entrance to a function, indents and points that out + /// + internal static void Enter(TraceSource traceSource, string method, string parameters) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + Enter(traceSource, method + "(" + parameters + ")"); + } + + /// + /// Logs entrance to a function, indents and points that out + /// + internal static void Enter(TraceSource traceSource, string msg) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + // Trace.CorrelationManager.StartLogicalOperation(); + PrintLine(traceSource, TraceEventType.Verbose, 0, msg); + } + + /// + /// Logs exit from a function + /// + internal static void Exit(TraceSource traceSource, object obj, string method, object retObject) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + string retValue = string.Empty; + if (retObject != null) + { + retValue = GetObjectName(retObject) + "#" + ValidationHelper.HashString(retObject); + } + Exit(traceSource, obj, method, retValue); + } + + /// + /// Logs exit from a function + /// + internal static void Exit(TraceSource traceSource, string obj, string method, object retObject) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + string retValue = string.Empty; + if (retObject != null) + { + retValue = GetObjectName(retObject) + "#" + ValidationHelper.HashString(retObject); + } + Exit(traceSource, obj, method, retValue); + } + + /// + /// Logs exit from a function + /// + internal static void Exit(TraceSource traceSource, object obj, string method, string retValue) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + Exit(traceSource, GetObjectName(obj) + "#" + ValidationHelper.HashString(obj), method, retValue); + } + + /// + /// Logs exit from a function + /// + internal static void Exit(TraceSource traceSource, string obj, string method, string retValue) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + if (!string.IsNullOrEmpty(retValue)) + { + retValue = "\t-> " + retValue; + } + Exit(traceSource, obj + "::" + method + "() " + retValue); + } + + /// + /// Logs exit from a function + /// + internal static void Exit(TraceSource traceSource, string method, string parameters) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + Exit(traceSource, method + "() " + parameters); + } + + /// + /// Logs exit from a function + /// + internal static void Exit(TraceSource traceSource, string msg) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + PrintLine(traceSource, TraceEventType.Verbose, 0, "Exiting " + msg); + // Trace.CorrelationManager.StopLogicalOperation(); + } + + /// + /// Logs Exception, restores indenting + /// + internal static void Exception(TraceSource traceSource, object obj, string method, Exception e) + { + if (!ValidateSettings(traceSource, TraceEventType.Error)) + { + return; + } + + string infoLine = SR.GetString(SR.net_log_exception, GetObjectLogHash(obj), method, e.Message); + if (!string.IsNullOrEmpty(e.StackTrace)) + { + infoLine += "\r\n" + e.StackTrace; + } + PrintLine(traceSource, TraceEventType.Error, 0, infoLine); + } + + /// + /// Logs an Info line + /// + internal static void PrintInfo(TraceSource traceSource, string msg) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + PrintLine(traceSource, TraceEventType.Information, 0, msg); + } + + /// + /// Logs an Info line + /// + internal static void PrintInfo(TraceSource traceSource, object obj, string msg) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + PrintLine(traceSource, TraceEventType.Information, 0, + GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) + + " - " + msg); + } + + /// + /// Logs an Info line + /// + internal static void PrintInfo(TraceSource traceSource, object obj, string method, string param) + { + if (!ValidateSettings(traceSource, TraceEventType.Information)) + { + return; + } + PrintLine(traceSource, TraceEventType.Information, 0, + GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) + + "::" + method + "(" + param + ")"); + } + + /// + /// Logs a Warning line + /// + internal static void PrintWarning(TraceSource traceSource, string msg) + { + if (!ValidateSettings(traceSource, TraceEventType.Warning)) + { + return; + } + PrintLine(traceSource, TraceEventType.Warning, 0, msg); + } + + /// + /// Logs a Warning line + /// + internal static void PrintWarning(TraceSource traceSource, object obj, string method, string msg) + { + if (!ValidateSettings(traceSource, TraceEventType.Warning)) + { + return; + } + PrintLine(traceSource, TraceEventType.Warning, 0, + GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) + + "::" + method + "() - " + msg); + } + + /// + /// Logs an Error line + /// + internal static void PrintError(TraceSource traceSource, string msg) + { + if (!ValidateSettings(traceSource, TraceEventType.Error)) + { + return; + } + PrintLine(traceSource, TraceEventType.Error, 0, msg); + } + + /// + /// Logs an Error line + /// + internal static void PrintError(TraceSource traceSource, object obj, string method, string msg) + { + if (!ValidateSettings(traceSource, TraceEventType.Error)) + { + return; + } + PrintLine(traceSource, TraceEventType.Error, 0, + GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) + + "::" + method + "() - " + msg); + } + + internal static string GetObjectLogHash(object obj) + { + return GetObjectName(obj) + "#" + ValidationHelper.HashString(obj); + } + + /// + /// Marhsalls a buffer ptr to an array and then dumps the byte array to the log + /// + internal static void Dump(TraceSource traceSource, object obj, string method, IntPtr bufferPtr, int length) + { + if (!ValidateSettings(traceSource, TraceEventType.Verbose) || bufferPtr == IntPtr.Zero || length < 0) + { + return; + } + byte[] buffer = new byte[length]; + Marshal.Copy(bufferPtr, buffer, 0, length); + Dump(traceSource, obj, method, buffer, 0, length); + } + + /// + /// Dumps a byte array to the log + /// + internal static void Dump(TraceSource traceSource, object obj, string method, byte[] buffer, int offset, int length) + { + if (!ValidateSettings(traceSource, TraceEventType.Verbose)) + { + return; + } + if (buffer == null) + { + PrintLine(traceSource, TraceEventType.Verbose, 0, "(null)"); + return; + } + if (offset > buffer.Length) + { + PrintLine(traceSource, TraceEventType.Verbose, 0, "(offset out of range)"); + return; + } + PrintLine(traceSource, TraceEventType.Verbose, 0, "Data from " + GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) + "::" + method); + int maxDumpSize = GetMaxDumpSizeSetting(traceSource); + if (length > maxDumpSize) + { + PrintLine(traceSource, TraceEventType.Verbose, 0, "(printing " + maxDumpSize.ToString(NumberFormatInfo.InvariantInfo) + " out of " + length.ToString(NumberFormatInfo.InvariantInfo) + ")"); + length = maxDumpSize; + } + if ((length < 0) || (length > buffer.Length - offset)) + { + length = buffer.Length - offset; + } + if (GetUseProtocolTextSetting(traceSource)) + { + string output = "<<" + HeaderEncoding.GetString(buffer, offset, length) + ">>"; + PrintLine(traceSource, TraceEventType.Verbose, 0, output); + return; + } + do + { + int n = Math.Min(length, 16); + string disp = String.Format(CultureInfo.CurrentCulture, "{0:X8} : ", offset); + for (int i = 0; i < n; ++i) + { + disp += String.Format(CultureInfo.CurrentCulture, "{0:X2}", buffer[offset + i]) + ((i == 7) ? '-' : ' '); + } + for (int i = n; i < 16; ++i) + { + disp += " "; + } + disp += ": "; + for (int i = 0; i < n; ++i) + { + disp += ((buffer[offset + i] < 0x20) || (buffer[offset + i] > 0x7e)) + ? '.' + : (char)(buffer[offset + i]); + } + PrintLine(traceSource, TraceEventType.Verbose, 0, disp); + offset += n; + length -= n; + } + while (length > 0); + } + + private class NclTraceSource : TraceSource + { + internal NclTraceSource(string name) : base(name) + { + } + /* + protected internal override string[] GetSupportedAttributes() + { + return Logging.SupportedAttributes; + }*/ + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs new file mode 100644 index 0000000000..dbbd6d5415 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs @@ -0,0 +1,580 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +// We have function based stack and thread based logging of basic behavior. We +// also now have the ability to run a "watch thread" which does basic hang detection +// and error-event based logging. The logging code buffers the callstack/picture +// of all COMNET threads, and upon error from an assert or a hang, it will open a file +// and dump the snapsnot. Future work will allow this to be configed by registry and +// to use Runtime based logging. We'd also like to have different levels of logging. + +namespace Microsoft.AspNet.Security.Windows +{ + using System; + + // BaseLoggingObject - used to disable logging, + // this is just a base class that does nothing. + + [Flags] + internal enum ThreadKinds + { + Unknown = 0x0000, + + // Mutually exclusive. + User = 0x0001, // Thread has entered via an API. + System = 0x0002, // Thread has entered via a system callback (e.g. completion port) or is our own thread. + + // Mutually exclusive. + Sync = 0x0004, // Thread should block. + Async = 0x0008, // Thread should not block. + + // Mutually exclusive, not always known for a user thread. Never changes. + Timer = 0x0010, // Thread is the timer thread. (Can't call user code.) + CompletionPort = 0x0020, // Thread is a ThreadPool completion-port thread. + Worker = 0x0040, // Thread is a ThreadPool worker thread. + Finalization = 0x0080, // Thread is the finalization thread. + Other = 0x0100, // Unknown source. + + OwnerMask = User | System, + SyncMask = Sync | Async, + SourceMask = Timer | CompletionPort | Worker | Finalization | Other, + + // Useful "macros" + SafeSources = SourceMask & ~(Timer | Finalization), // Methods that "unsafe" sources can call must be explicitly marked. + ThreadPool = CompletionPort | Worker, // Like Thread.CurrentThread.IsThreadPoolThread + } + + internal class BaseLoggingObject + { + internal BaseLoggingObject() + { + } + + internal virtual void EnterFunc(string funcname) + { + } + + internal virtual void LeaveFunc(string funcname) + { + } + + internal virtual void DumpArrayToConsole() + { + } + + internal virtual void PrintLine(string msg) + { + } + + internal virtual void DumpArray(bool shouldClose) + { + } + + internal virtual void DumpArrayToFile(bool shouldClose) + { + } + + internal virtual void Flush() + { + } + + internal virtual void Flush(bool close) + { + } + + internal virtual void LoggingMonitorTick() + { + } + + internal virtual void Dump(byte[] buffer) + { + } + + internal virtual void Dump(byte[] buffer, int length) + { + } + + internal virtual void Dump(byte[] buffer, int offset, int length) + { + } + + internal virtual void Dump(IntPtr pBuffer, int offset, int length) + { + } + } // class BaseLoggingObject + +#if TRAVE + /// + /// + /// + internal class LoggingObject : BaseLoggingObject { + public ArrayList _Logarray; + private Hashtable _ThreadNesting; + private int _AddCount; + private StreamWriter _Stream; + private int _IamAlive; + private int _LastIamAlive; + private bool _Finalized = false; + private double _NanosecondsPerTick; + private int _StartMilliseconds; + private long _StartTicks; + + internal LoggingObject() : base() { + _Logarray = new ArrayList(); + _ThreadNesting = new Hashtable(); + _AddCount = 0; + _IamAlive = 0; + _LastIamAlive = -1; + + if (GlobalLog.s_UsePerfCounter) { + long ticksPerSecond; + SafeNativeMethods.QueryPerformanceFrequency(out ticksPerSecond); + _NanosecondsPerTick = 10000000.0/(double)ticksPerSecond; + SafeNativeMethods.QueryPerformanceCounter(out _StartTicks); + } else { + _StartMilliseconds = Environment.TickCount; + } + } + + // + // LoggingMonitorTick - this function is run from the monitor thread, + // and used to check to see if there any hangs, ie no logging + // activitity + // + + internal override void LoggingMonitorTick() { + if ( _LastIamAlive == _IamAlive ) { + PrintLine("================= Error TIMEOUT - HANG DETECTED ================="); + DumpArray(true); + } + _LastIamAlive = _IamAlive; + } + + internal override void EnterFunc(string funcname) { + if (_Finalized) { + return; + } + IncNestingCount(); + ValidatePush(funcname); + PrintLine(funcname); + } + + internal override void LeaveFunc(string funcname) { + if (_Finalized) { + return; + } + PrintLine(funcname); + DecNestingCount(); + ValidatePop(funcname); + } + + internal override void DumpArrayToConsole() { + for (int i=0; i < _Logarray.Count; i++) { + Console.WriteLine((string) _Logarray[i]); + } + } + + internal override void PrintLine(string msg) { + if (_Finalized) { + return; + } + string spc = ""; + + _IamAlive++; + + spc = GetNestingString(); + + string tickString = ""; + + if (GlobalLog.s_UsePerfCounter) { + long nowTicks; + SafeNativeMethods.QueryPerformanceCounter(out nowTicks); + if (_StartTicks>nowTicks) { // counter reset, restart from 0 + _StartTicks = nowTicks; + } + nowTicks -= _StartTicks; + if (GlobalLog.s_UseTimeSpan) { + tickString = new TimeSpan((long)(nowTicks*_NanosecondsPerTick)).ToString(); + // note: TimeSpan().ToString() doesn't return the uSec part + // if its 0. .ToString() returns [H*]HH:MM:SS:uuuuuuu, hence 16 + if (tickString.Length < 16) { + tickString += ".0000000"; + } + } + else { + tickString = ((double)nowTicks*_NanosecondsPerTick/10000).ToString("f3"); + } + } + else { + int nowMilliseconds = Environment.TickCount; + if (_StartMilliseconds>nowMilliseconds) { + _StartMilliseconds = nowMilliseconds; + } + nowMilliseconds -= _StartMilliseconds; + if (GlobalLog.s_UseTimeSpan) { + tickString = new TimeSpan(nowMilliseconds*10000).ToString(); + // note: TimeSpan().ToString() doesn't return the uSec part + // if its 0. .ToString() returns [H*]HH:MM:SS:uuuuuuu, hence 16 + if (tickString.Length < 16) { + tickString += ".0000000"; + } + } + else { + tickString = nowMilliseconds.ToString(); + } + } + + uint threadId = 0; + + if (GlobalLog.s_UseThreadId) { + try { + object threadData = Thread.GetData(GlobalLog.s_ThreadIdSlot); + if (threadData!= null) { + threadId = (uint)threadData; + } + + } + catch(Exception exception) { + if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { + throw; + } + } + if (threadId == 0) { + threadId = UnsafeNclNativeMethods.GetCurrentThreadId(); + Thread.SetData(GlobalLog.s_ThreadIdSlot, threadId); + } + } + if (threadId == 0) { + threadId = (uint)Thread.CurrentThread.GetHashCode(); + } + + string str = "[" + threadId.ToString("x8") + "]" + " (" +tickString+ ") " + spc + msg; + + lock(this) { + _AddCount++; + _Logarray.Add(str); + int MaxLines = GlobalLog.s_DumpToConsole ? 0 : GlobalLog.MaxLinesBeforeSave; + if (_AddCount > MaxLines) { + _AddCount = 0; + DumpArray(false); + _Logarray = new ArrayList(); + } + } + } + + internal override void DumpArray(bool shouldClose) { + if ( GlobalLog.s_DumpToConsole ) { + DumpArrayToConsole(); + } else { + DumpArrayToFile(shouldClose); + } + } + + internal unsafe override void Dump(byte[] buffer, int offset, int length) { + //if (!GlobalLog.s_DumpWebData) { + // return; + //} + if (buffer==null) { + PrintLine("(null)"); + return; + } + if (offset > buffer.Length) { + PrintLine("(offset out of range)"); + return; + } + if (length > GlobalLog.s_MaxDumpSize) { + PrintLine("(printing " + GlobalLog.s_MaxDumpSize.ToString() + " out of " + length.ToString() + ")"); + length = GlobalLog.s_MaxDumpSize; + } + if ((length < 0) || (length > buffer.Length - offset)) { + length = buffer.Length - offset; + } + fixed (byte* pBuffer = buffer) { + Dump((IntPtr)pBuffer, offset, length); + } + } + + internal unsafe override void Dump(IntPtr pBuffer, int offset, int length) { + //if (!GlobalLog.s_DumpWebData) { + // return; + //} + if (pBuffer==IntPtr.Zero || length<0) { + PrintLine("(null)"); + return; + } + if (length > GlobalLog.s_MaxDumpSize) { + PrintLine("(printing " + GlobalLog.s_MaxDumpSize.ToString() + " out of " + length.ToString() + ")"); + length = GlobalLog.s_MaxDumpSize; + } + byte* buffer = (byte*)pBuffer + offset; + Dump(buffer, length); + } + + unsafe void Dump(byte* buffer, int length) { + do { + int offset = 0; + int n = Math.Min(length, 16); + string disp = ((IntPtr)buffer).ToString("X8") + " : " + offset.ToString("X8") + " : "; + byte current; + for (int i = 0; i < n; ++i) { + current = *(buffer + i); + disp += current.ToString("X2") + ((i == 7) ? '-' : ' '); + } + for (int i = n; i < 16; ++i) { + disp += " "; + } + disp += ": "; + for (int i = 0; i < n; ++i) { + current = *(buffer + i); + disp += ((current < 0x20) || (current > 0x7e)) ? '.' : (char)current; + } + PrintLine(disp); + offset += n; + buffer += n; + length -= n; + } while (length > 0); + } + + // SECURITY: This is dev-debugging class and we need some permissions + // to use it under trust-restricted environment as well. + [PermissionSet(SecurityAction.Assert, Name="FullTrust")] + internal override void DumpArrayToFile(bool shouldClose) { + lock (this) { + if (!shouldClose) { + if (_Stream==null) { + string mainLogFileRoot = GlobalLog.s_RootDirectory + "System.Net"; + string mainLogFile = mainLogFileRoot; + for (int k=0; k<20; k++) { + if (k>0) { + mainLogFile = mainLogFileRoot + "." + k.ToString(); + } + string fileName = mainLogFile + ".log"; + if (!File.Exists(fileName)) { + try { + _Stream = new StreamWriter(fileName); + break; + } + catch (Exception exception) { + if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { + throw; + } + if (exception is SecurityException || exception is UnauthorizedAccessException) { + // can't be CAS (we assert) this is an ACL issue + break; + } + } + } + } + if (_Stream==null) { + _Stream = StreamWriter.Null; + } + // write a header with information about the Process and the AppDomain + _Stream.Write("# MachineName: " + Environment.MachineName + "\r\n"); + _Stream.Write("# ProcessName: " + Process.GetCurrentProcess().ProcessName + " (pid: " + Process.GetCurrentProcess().Id + ")\r\n"); + _Stream.Write("# AppDomainId: " + AppDomain.CurrentDomain.Id + "\r\n"); + _Stream.Write("# CurrentIdentity: " + WindowsIdentity.GetCurrent().Name + "\r\n"); + _Stream.Write("# CommandLine: " + Environment.CommandLine + "\r\n"); + _Stream.Write("# ClrVersion: " + Environment.Version + "\r\n"); + _Stream.Write("# CreationDate: " + DateTime.Now.ToString("g") + "\r\n"); + } + } + try { + if (_Logarray!=null) { + for (int i=0; i<_Logarray.Count; i++) { + _Stream.Write((string)_Logarray[i]); + _Stream.Write("\r\n"); + } + + if (_Logarray.Count > 0 && _Stream != null) + _Stream.Flush(); + } + } + catch (Exception exception) { + if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { + throw; + } + } + if (shouldClose && _Stream!=null) { + try { + _Stream.Close(); + } + catch (ObjectDisposedException) { } + _Stream = null; + } + } + } + + internal override void Flush() { + Flush(false); + } + + internal override void Flush(bool close) { + lock (this) { + if (!GlobalLog.s_DumpToConsole) { + DumpArrayToFile(close); + _AddCount = 0; + } + } + } + + private class ThreadInfoData { + public ThreadInfoData(string indent) { + Indent = indent; + NestingStack = new Stack(); + } + public string Indent; + public Stack NestingStack; + }; + + string IndentString { + get { + string indent = " "; + Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()]; + if (!GlobalLog.s_DebugCallNesting) { + if (obj == null) { + _ThreadNesting[Thread.CurrentThread.GetHashCode()] = indent; + } else { + indent = (String) obj; + } + } else { + ThreadInfoData threadInfo = obj as ThreadInfoData; + if (threadInfo == null) { + threadInfo = new ThreadInfoData(indent); + _ThreadNesting[Thread.CurrentThread.GetHashCode()] = threadInfo; + } + indent = threadInfo.Indent; + } + return indent; + } + set { + Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()]; + if (obj == null) { + return; + } + if (!GlobalLog.s_DebugCallNesting) { + _ThreadNesting[Thread.CurrentThread.GetHashCode()] = value; + } else { + ThreadInfoData threadInfo = obj as ThreadInfoData; + if (threadInfo == null) { + threadInfo = new ThreadInfoData(value); + _ThreadNesting[Thread.CurrentThread.GetHashCode()] = threadInfo; + } + threadInfo.Indent = value; + } + } + } + + [System.Diagnostics.Conditional("TRAVE")] + private void IncNestingCount() { + IndentString = IndentString + " "; + } + + [System.Diagnostics.Conditional("TRAVE")] + private void DecNestingCount() { + string indent = IndentString; + if (indent.Length>1) { + try { + indent = indent.Substring(1); + } + catch { + indent = string.Empty; + } + } + if (indent.Length==0) { + indent = "< "; + } + IndentString = indent; + } + + private string GetNestingString() { + return IndentString; + } + + [System.Diagnostics.Conditional("TRAVE")] + private void ValidatePush(string name) { + if (GlobalLog.s_DebugCallNesting) { + Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()]; + ThreadInfoData threadInfo = obj as ThreadInfoData; + if (threadInfo == null) { + return; + } + threadInfo.NestingStack.Push(name); + } + } + + [System.Diagnostics.Conditional("TRAVE")] + private void ValidatePop(string name) { + if (GlobalLog.s_DebugCallNesting) { + try { + Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()]; + ThreadInfoData threadInfo = obj as ThreadInfoData; + if (threadInfo == null) { + return; + } + if (threadInfo.NestingStack.Count == 0) { + PrintLine("++++====" + "Poped Empty Stack for :"+name); + } + string popedName = (string) threadInfo.NestingStack.Pop(); + string [] parsedList = popedName.Split(new char [] {'(',')',' ','.',':',',','#'}); + foreach (string element in parsedList) { + if (element != null && element.Length > 1 && name.IndexOf(element) != -1) { + return; + } + } + PrintLine("++++====" + "Expected:" + popedName + ": got :" + name + ": StackSize:"+threadInfo.NestingStack.Count); + // relevel the stack + while(threadInfo.NestingStack.Count>0) { + string popedName2 = (string) threadInfo.NestingStack.Pop(); + string [] parsedList2 = popedName2.Split(new char [] {'(',')',' ','.',':',',','#'}); + foreach (string element2 in parsedList2) { + if (element2 != null && element2.Length > 1 && name.IndexOf(element2) != -1) { + return; + } + } + } + } + catch { + PrintLine("++++====" + "ValidatePop failed for: "+name); + } + } + } + + + ~LoggingObject() { + if(!_Finalized) { + _Finalized = true; + lock(this) { + DumpArray(true); + } + } + } + + + } // class LoggingObject + + internal static class TraveHelper { + private static readonly string Hexizer = "0x{0:x}"; + internal static string ToHex(object value) { + return String.Format(Hexizer, value); + } + } +#endif // TRAVE + +#if TRAVE + internal class IntegerSwitch : BooleanSwitch { + public IntegerSwitch(string switchName, string switchDescription) : base(switchName, switchDescription) { + } + public new int Value { + get { + return base.SwitchSetting; + } + } + } + +#endif + + // class GlobalLog +} // namespace System.Net diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs new file mode 100644 index 0000000000..5486b33602 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs @@ -0,0 +1,630 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace System +{ + using System; + using System.Reflection; + using System.Globalization; + using System.Resources; + using System.Text; + using System.Threading; + using System.Security.Permissions; + using System.ComponentModel; + + /// + /// AutoGenerated resource class. Usage: + /// string s = SR.GetString(SR.MyIdenfitier); + /// + internal sealed class SR + { + internal const string security_ExtendedProtection_NoOSSupport = "security_ExtendedProtection_NoOSSupport"; + internal const string net_nonClsCompliantException = "net_nonClsCompliantException"; + internal const string net_illegalConfigWith = "net_illegalConfigWith"; + internal const string net_illegalConfigWithout = "net_illegalConfigWithout"; + internal const string net_baddate = "net_baddate"; + internal const string net_writestarted = "net_writestarted"; + internal const string net_clsmall = "net_clsmall"; + internal const string net_reqsubmitted = "net_reqsubmitted"; + internal const string net_rspsubmitted = "net_rspsubmitted"; + internal const string net_ftp_no_http_cmd = "net_ftp_no_http_cmd"; + internal const string net_ftp_invalid_method_name = "net_ftp_invalid_method_name"; + internal const string net_ftp_invalid_renameto = "net_ftp_invalid_renameto"; + internal const string net_ftp_no_defaultcreds = "net_ftp_no_defaultcreds"; + internal const string net_ftpnoresponse = "net_ftpnoresponse"; + internal const string net_ftp_response_invalid_format = "net_ftp_response_invalid_format"; + internal const string net_ftp_no_offsetforhttp = "net_ftp_no_offsetforhttp"; + internal const string net_ftp_invalid_uri = "net_ftp_invalid_uri"; + internal const string net_ftp_invalid_status_response = "net_ftp_invalid_status_response"; + internal const string net_ftp_server_failed_passive = "net_ftp_server_failed_passive"; + internal const string net_ftp_active_address_different = "net_ftp_active_address_different"; + internal const string net_ftp_proxy_does_not_support_ssl = "net_ftp_proxy_does_not_support_ssl"; + internal const string net_ftp_invalid_response_filename = "net_ftp_invalid_response_filename"; + internal const string net_ftp_unsupported_method = "net_ftp_unsupported_method"; + internal const string net_resubmitcanceled = "net_resubmitcanceled"; + internal const string net_redirect_perm = "net_redirect_perm"; + internal const string net_resubmitprotofailed = "net_resubmitprotofailed"; + internal const string net_needchunked = "net_needchunked"; + internal const string net_nochunked = "net_nochunked"; + internal const string net_nochunkuploadonhttp10 = "net_nochunkuploadonhttp10"; + internal const string net_connarg = "net_connarg"; + internal const string net_no100 = "net_no100"; + internal const string net_fromto = "net_fromto"; + internal const string net_rangetoosmall = "net_rangetoosmall"; + internal const string net_entitytoobig = "net_entitytoobig"; + internal const string net_invalidversion = "net_invalidversion"; + internal const string net_invalidstatus = "net_invalidstatus"; + internal const string net_toosmall = "net_toosmall"; + internal const string net_toolong = "net_toolong"; + internal const string net_connclosed = "net_connclosed"; + internal const string net_noseek = "net_noseek"; + internal const string net_servererror = "net_servererror"; + internal const string net_nouploadonget = "net_nouploadonget"; + internal const string net_mutualauthfailed = "net_mutualauthfailed"; + internal const string net_invasync = "net_invasync"; + internal const string net_inasync = "net_inasync"; + internal const string net_mustbeuri = "net_mustbeuri"; + internal const string net_format_shexp = "net_format_shexp"; + internal const string net_cannot_load_proxy_helper = "net_cannot_load_proxy_helper"; + internal const string net_invalid_host = "net_invalid_host"; + internal const string net_repcall = "net_repcall"; + internal const string net_wrongversion = "net_wrongversion"; + internal const string net_badmethod = "net_badmethod"; + internal const string net_io_notenoughbyteswritten = "net_io_notenoughbyteswritten"; + internal const string net_io_timeout_use_ge_zero = "net_io_timeout_use_ge_zero"; + internal const string net_io_timeout_use_gt_zero = "net_io_timeout_use_gt_zero"; + internal const string net_io_no_0timeouts = "net_io_no_0timeouts"; + internal const string net_requestaborted = "net_requestaborted"; + internal const string net_tooManyRedirections = "net_tooManyRedirections"; + internal const string net_authmodulenotregistered = "net_authmodulenotregistered"; + internal const string net_authschemenotregistered = "net_authschemenotregistered"; + internal const string net_proxyschemenotsupported = "net_proxyschemenotsupported"; + internal const string net_maxsrvpoints = "net_maxsrvpoints"; + internal const string net_unknown_prefix = "net_unknown_prefix"; + internal const string net_notconnected = "net_notconnected"; + internal const string net_notstream = "net_notstream"; + internal const string net_timeout = "net_timeout"; + internal const string net_nocontentlengthonget = "net_nocontentlengthonget"; + internal const string net_contentlengthmissing = "net_contentlengthmissing"; + internal const string net_nonhttpproxynotallowed = "net_nonhttpproxynotallowed"; + internal const string net_nottoken = "net_nottoken"; + internal const string net_rangetype = "net_rangetype"; + internal const string net_need_writebuffering = "net_need_writebuffering"; + internal const string net_securitypackagesupport = "net_securitypackagesupport"; + internal const string net_securityprotocolnotsupported = "net_securityprotocolnotsupported"; + internal const string net_nodefaultcreds = "net_nodefaultcreds"; + internal const string net_stopped = "net_stopped"; + internal const string net_udpconnected = "net_udpconnected"; + internal const string net_readonlystream = "net_readonlystream"; + internal const string net_writeonlystream = "net_writeonlystream"; + internal const string net_no_concurrent_io_allowed = "net_no_concurrent_io_allowed"; + internal const string net_needmorethreads = "net_needmorethreads"; + internal const string net_MethodNotImplementedException = "net_MethodNotImplementedException"; + internal const string net_PropertyNotImplementedException = "net_PropertyNotImplementedException"; + internal const string net_MethodNotSupportedException = "net_MethodNotSupportedException"; + internal const string net_PropertyNotSupportedException = "net_PropertyNotSupportedException"; + internal const string net_ProtocolNotSupportedException = "net_ProtocolNotSupportedException"; + internal const string net_SelectModeNotSupportedException = "net_SelectModeNotSupportedException"; + internal const string net_InvalidSocketHandle = "net_InvalidSocketHandle"; + internal const string net_InvalidAddressFamily = "net_InvalidAddressFamily"; + internal const string net_InvalidEndPointAddressFamily = "net_InvalidEndPointAddressFamily"; + internal const string net_InvalidSocketAddressSize = "net_InvalidSocketAddressSize"; + internal const string net_invalidAddressList = "net_invalidAddressList"; + internal const string net_invalidPingBufferSize = "net_invalidPingBufferSize"; + internal const string net_cant_perform_during_shutdown = "net_cant_perform_during_shutdown"; + internal const string net_cant_create_environment = "net_cant_create_environment"; + internal const string net_completed_result = "net_completed_result"; + internal const string net_protocol_invalid_family = "net_protocol_invalid_family"; + internal const string net_protocol_invalid_multicast_family = "net_protocol_invalid_multicast_family"; + internal const string net_empty_osinstalltype = "net_empty_osinstalltype"; + internal const string net_unknown_osinstalltype = "net_unknown_osinstalltype"; + internal const string net_cant_determine_osinstalltype = "net_cant_determine_osinstalltype"; + internal const string net_osinstalltype = "net_osinstalltype"; + internal const string net_entire_body_not_written = "net_entire_body_not_written"; + internal const string net_must_provide_request_body = "net_must_provide_request_body"; + internal const string net_ssp_dont_support_cbt = "net_ssp_dont_support_cbt"; + internal const string net_sockets_zerolist = "net_sockets_zerolist"; + internal const string net_sockets_blocking = "net_sockets_blocking"; + internal const string net_sockets_useblocking = "net_sockets_useblocking"; + internal const string net_sockets_select = "net_sockets_select"; + internal const string net_sockets_toolarge_select = "net_sockets_toolarge_select"; + internal const string net_sockets_empty_select = "net_sockets_empty_select"; + internal const string net_sockets_mustbind = "net_sockets_mustbind"; + internal const string net_sockets_mustlisten = "net_sockets_mustlisten"; + internal const string net_sockets_mustnotlisten = "net_sockets_mustnotlisten"; + internal const string net_sockets_mustnotbebound = "net_sockets_mustnotbebound"; + internal const string net_sockets_namedmustnotbebound = "net_sockets_namedmustnotbebound"; + internal const string net_sockets_invalid_socketinformation = "net_sockets_invalid_socketinformation"; + internal const string net_sockets_invalid_ipaddress_length = "net_sockets_invalid_ipaddress_length"; + internal const string net_sockets_invalid_optionValue = "net_sockets_invalid_optionValue"; + internal const string net_sockets_invalid_optionValue_all = "net_sockets_invalid_optionValue_all"; + internal const string net_sockets_invalid_dnsendpoint = "net_sockets_invalid_dnsendpoint"; + internal const string net_sockets_disconnectedConnect = "net_sockets_disconnectedConnect"; + internal const string net_sockets_disconnectedAccept = "net_sockets_disconnectedAccept"; + internal const string net_tcplistener_mustbestopped = "net_tcplistener_mustbestopped"; + internal const string net_sockets_no_duplicate_async = "net_sockets_no_duplicate_async"; + internal const string net_socketopinprogress = "net_socketopinprogress"; + internal const string net_buffercounttoosmall = "net_buffercounttoosmall"; + internal const string net_multibuffernotsupported = "net_multibuffernotsupported"; + internal const string net_ambiguousbuffers = "net_ambiguousbuffers"; + internal const string net_sockets_ipv6only = "net_sockets_ipv6only"; + internal const string net_perfcounter_initialized_success = "net_perfcounter_initialized_success"; + internal const string net_perfcounter_initialized_error = "net_perfcounter_initialized_error"; + internal const string net_perfcounter_nocategory = "net_perfcounter_nocategory"; + internal const string net_perfcounter_initialization_started = "net_perfcounter_initialization_started"; + internal const string net_perfcounter_cant_queue_workitem = "net_perfcounter_cant_queue_workitem"; + internal const string net_config_proxy = "net_config_proxy"; + internal const string net_config_proxy_module_not_public = "net_config_proxy_module_not_public"; + internal const string net_config_authenticationmodules = "net_config_authenticationmodules"; + internal const string net_config_webrequestmodules = "net_config_webrequestmodules"; + internal const string net_config_requestcaching = "net_config_requestcaching"; + internal const string net_config_section_permission = "net_config_section_permission"; + internal const string net_config_element_permission = "net_config_element_permission"; + internal const string net_config_property_permission = "net_config_property_permission"; + internal const string net_WebResponseParseError_InvalidHeaderName = "net_WebResponseParseError_InvalidHeaderName"; + internal const string net_WebResponseParseError_InvalidContentLength = "net_WebResponseParseError_InvalidContentLength"; + internal const string net_WebResponseParseError_IncompleteHeaderLine = "net_WebResponseParseError_IncompleteHeaderLine"; + internal const string net_WebResponseParseError_CrLfError = "net_WebResponseParseError_CrLfError"; + internal const string net_WebResponseParseError_InvalidChunkFormat = "net_WebResponseParseError_InvalidChunkFormat"; + internal const string net_WebResponseParseError_UnexpectedServerResponse = "net_WebResponseParseError_UnexpectedServerResponse"; + internal const string net_webstatus_Success = "net_webstatus_Success"; + internal const string net_webstatus_NameResolutionFailure = "net_webstatus_NameResolutionFailure"; + internal const string net_webstatus_ConnectFailure = "net_webstatus_ConnectFailure"; + internal const string net_webstatus_ReceiveFailure = "net_webstatus_ReceiveFailure"; + internal const string net_webstatus_SendFailure = "net_webstatus_SendFailure"; + internal const string net_webstatus_PipelineFailure = "net_webstatus_PipelineFailure"; + internal const string net_webstatus_RequestCanceled = "net_webstatus_RequestCanceled"; + internal const string net_webstatus_ConnectionClosed = "net_webstatus_ConnectionClosed"; + internal const string net_webstatus_TrustFailure = "net_webstatus_TrustFailure"; + internal const string net_webstatus_SecureChannelFailure = "net_webstatus_SecureChannelFailure"; + internal const string net_webstatus_ServerProtocolViolation = "net_webstatus_ServerProtocolViolation"; + internal const string net_webstatus_KeepAliveFailure = "net_webstatus_KeepAliveFailure"; + internal const string net_webstatus_ProxyNameResolutionFailure = "net_webstatus_ProxyNameResolutionFailure"; + internal const string net_webstatus_MessageLengthLimitExceeded = "net_webstatus_MessageLengthLimitExceeded"; + internal const string net_webstatus_CacheEntryNotFound = "net_webstatus_CacheEntryNotFound"; + internal const string net_webstatus_RequestProhibitedByCachePolicy = "net_webstatus_RequestProhibitedByCachePolicy"; + internal const string net_webstatus_Timeout = "net_webstatus_Timeout"; + internal const string net_webstatus_RequestProhibitedByProxy = "net_webstatus_RequestProhibitedByProxy"; + internal const string net_InvalidStatusCode = "net_InvalidStatusCode"; + internal const string net_ftpstatuscode_ServiceNotAvailable = "net_ftpstatuscode_ServiceNotAvailable"; + internal const string net_ftpstatuscode_CantOpenData = "net_ftpstatuscode_CantOpenData"; + internal const string net_ftpstatuscode_ConnectionClosed = "net_ftpstatuscode_ConnectionClosed"; + internal const string net_ftpstatuscode_ActionNotTakenFileUnavailableOrBusy = "net_ftpstatuscode_ActionNotTakenFileUnavailableOrBusy"; + internal const string net_ftpstatuscode_ActionAbortedLocalProcessingError = "net_ftpstatuscode_ActionAbortedLocalProcessingError"; + internal const string net_ftpstatuscode_ActionNotTakenInsufficentSpace = "net_ftpstatuscode_ActionNotTakenInsufficentSpace"; + internal const string net_ftpstatuscode_CommandSyntaxError = "net_ftpstatuscode_CommandSyntaxError"; + internal const string net_ftpstatuscode_ArgumentSyntaxError = "net_ftpstatuscode_ArgumentSyntaxError"; + internal const string net_ftpstatuscode_CommandNotImplemented = "net_ftpstatuscode_CommandNotImplemented"; + internal const string net_ftpstatuscode_BadCommandSequence = "net_ftpstatuscode_BadCommandSequence"; + internal const string net_ftpstatuscode_NotLoggedIn = "net_ftpstatuscode_NotLoggedIn"; + internal const string net_ftpstatuscode_AccountNeeded = "net_ftpstatuscode_AccountNeeded"; + internal const string net_ftpstatuscode_ActionNotTakenFileUnavailable = "net_ftpstatuscode_ActionNotTakenFileUnavailable"; + internal const string net_ftpstatuscode_ActionAbortedUnknownPageType = "net_ftpstatuscode_ActionAbortedUnknownPageType"; + internal const string net_ftpstatuscode_FileActionAborted = "net_ftpstatuscode_FileActionAborted"; + internal const string net_ftpstatuscode_ActionNotTakenFilenameNotAllowed = "net_ftpstatuscode_ActionNotTakenFilenameNotAllowed"; + internal const string net_httpstatuscode_NoContent = "net_httpstatuscode_NoContent"; + internal const string net_httpstatuscode_NonAuthoritativeInformation = "net_httpstatuscode_NonAuthoritativeInformation"; + internal const string net_httpstatuscode_ResetContent = "net_httpstatuscode_ResetContent"; + internal const string net_httpstatuscode_PartialContent = "net_httpstatuscode_PartialContent"; + internal const string net_httpstatuscode_MultipleChoices = "net_httpstatuscode_MultipleChoices"; + internal const string net_httpstatuscode_Ambiguous = "net_httpstatuscode_Ambiguous"; + internal const string net_httpstatuscode_MovedPermanently = "net_httpstatuscode_MovedPermanently"; + internal const string net_httpstatuscode_Moved = "net_httpstatuscode_Moved"; + internal const string net_httpstatuscode_Found = "net_httpstatuscode_Found"; + internal const string net_httpstatuscode_Redirect = "net_httpstatuscode_Redirect"; + internal const string net_httpstatuscode_SeeOther = "net_httpstatuscode_SeeOther"; + internal const string net_httpstatuscode_RedirectMethod = "net_httpstatuscode_RedirectMethod"; + internal const string net_httpstatuscode_NotModified = "net_httpstatuscode_NotModified"; + internal const string net_httpstatuscode_UseProxy = "net_httpstatuscode_UseProxy"; + internal const string net_httpstatuscode_TemporaryRedirect = "net_httpstatuscode_TemporaryRedirect"; + internal const string net_httpstatuscode_RedirectKeepVerb = "net_httpstatuscode_RedirectKeepVerb"; + internal const string net_httpstatuscode_BadRequest = "net_httpstatuscode_BadRequest"; + internal const string net_httpstatuscode_Unauthorized = "net_httpstatuscode_Unauthorized"; + internal const string net_httpstatuscode_PaymentRequired = "net_httpstatuscode_PaymentRequired"; + internal const string net_httpstatuscode_Forbidden = "net_httpstatuscode_Forbidden"; + internal const string net_httpstatuscode_NotFound = "net_httpstatuscode_NotFound"; + internal const string net_httpstatuscode_MethodNotAllowed = "net_httpstatuscode_MethodNotAllowed"; + internal const string net_httpstatuscode_NotAcceptable = "net_httpstatuscode_NotAcceptable"; + internal const string net_httpstatuscode_ProxyAuthenticationRequired = "net_httpstatuscode_ProxyAuthenticationRequired"; + internal const string net_httpstatuscode_RequestTimeout = "net_httpstatuscode_RequestTimeout"; + internal const string net_httpstatuscode_Conflict = "net_httpstatuscode_Conflict"; + internal const string net_httpstatuscode_Gone = "net_httpstatuscode_Gone"; + internal const string net_httpstatuscode_LengthRequired = "net_httpstatuscode_LengthRequired"; + internal const string net_httpstatuscode_InternalServerError = "net_httpstatuscode_InternalServerError"; + internal const string net_httpstatuscode_NotImplemented = "net_httpstatuscode_NotImplemented"; + internal const string net_httpstatuscode_BadGateway = "net_httpstatuscode_BadGateway"; + internal const string net_httpstatuscode_ServiceUnavailable = "net_httpstatuscode_ServiceUnavailable"; + internal const string net_httpstatuscode_GatewayTimeout = "net_httpstatuscode_GatewayTimeout"; + internal const string net_httpstatuscode_HttpVersionNotSupported = "net_httpstatuscode_HttpVersionNotSupported"; + internal const string net_uri_BadScheme = "net_uri_BadScheme"; + internal const string net_uri_BadFormat = "net_uri_BadFormat"; + internal const string net_uri_BadUserPassword = "net_uri_BadUserPassword"; + internal const string net_uri_BadHostName = "net_uri_BadHostName"; + internal const string net_uri_BadAuthority = "net_uri_BadAuthority"; + internal const string net_uri_BadAuthorityTerminator = "net_uri_BadAuthorityTerminator"; + internal const string net_uri_EmptyUri = "net_uri_EmptyUri"; + internal const string net_uri_BadString = "net_uri_BadString"; + internal const string net_uri_MustRootedPath = "net_uri_MustRootedPath"; + internal const string net_uri_BadPort = "net_uri_BadPort"; + internal const string net_uri_SizeLimit = "net_uri_SizeLimit"; + internal const string net_uri_SchemeLimit = "net_uri_SchemeLimit"; + internal const string net_uri_NotAbsolute = "net_uri_NotAbsolute"; + internal const string net_uri_PortOutOfRange = "net_uri_PortOutOfRange"; + internal const string net_uri_UserDrivenParsing = "net_uri_UserDrivenParsing"; + internal const string net_uri_AlreadyRegistered = "net_uri_AlreadyRegistered"; + internal const string net_uri_NeedFreshParser = "net_uri_NeedFreshParser"; + internal const string net_uri_CannotCreateRelative = "net_uri_CannotCreateRelative"; + internal const string net_uri_InvalidUriKind = "net_uri_InvalidUriKind"; + internal const string net_uri_BadUnicodeHostForIdn = "net_uri_BadUnicodeHostForIdn"; + internal const string net_uri_GenericAuthorityNotDnsSafe = "net_uri_GenericAuthorityNotDnsSafe"; + internal const string net_uri_NotJustSerialization = "net_uri_NotJustSerialization"; + internal const string net_emptystringset = "net_emptystringset"; + internal const string net_emptystringcall = "net_emptystringcall"; + internal const string net_headers_req = "net_headers_req"; + internal const string net_headers_rsp = "net_headers_rsp"; + internal const string net_headers_toolong = "net_headers_toolong"; + internal const string net_WebHeaderInvalidControlChars = "net_WebHeaderInvalidControlChars"; + internal const string net_WebHeaderInvalidCRLFChars = "net_WebHeaderInvalidCRLFChars"; + internal const string net_WebHeaderInvalidHeaderChars = "net_WebHeaderInvalidHeaderChars"; + internal const string net_WebHeaderInvalidNonAsciiChars = "net_WebHeaderInvalidNonAsciiChars"; + internal const string net_WebHeaderMissingColon = "net_WebHeaderMissingColon"; + internal const string net_headerrestrict = "net_headerrestrict"; + internal const string net_io_completionportwasbound = "net_io_completionportwasbound"; + internal const string net_io_writefailure = "net_io_writefailure"; + internal const string net_io_readfailure = "net_io_readfailure"; + internal const string net_io_connectionclosed = "net_io_connectionclosed"; + internal const string net_io_transportfailure = "net_io_transportfailure"; + internal const string net_io_internal_bind = "net_io_internal_bind"; + internal const string net_io_invalidasyncresult = "net_io_invalidasyncresult"; + internal const string net_io_invalidnestedcall = "net_io_invalidnestedcall"; + internal const string net_io_invalidendcall = "net_io_invalidendcall"; + internal const string net_io_must_be_rw_stream = "net_io_must_be_rw_stream"; + internal const string net_io_header_id = "net_io_header_id"; + internal const string net_io_out_range = "net_io_out_range"; + internal const string net_io_encrypt = "net_io_encrypt"; + internal const string net_io_decrypt = "net_io_decrypt"; + internal const string net_io_read = "net_io_read"; + internal const string net_io_write = "net_io_write"; + internal const string net_io_eof = "net_io_eof"; + internal const string net_io_async_result = "net_io_async_result"; + internal const string net_listener_mustcall = "net_listener_mustcall"; + internal const string net_listener_mustcompletecall = "net_listener_mustcompletecall"; + internal const string net_listener_callinprogress = "net_listener_callinprogress"; + internal const string net_listener_scheme = "net_listener_scheme"; + internal const string net_listener_host = "net_listener_host"; + internal const string net_listener_slash = "net_listener_slash"; + internal const string net_listener_repcall = "net_listener_repcall"; + internal const string net_listener_invalid_cbt_type = "net_listener_invalid_cbt_type"; + internal const string net_listener_no_spns = "net_listener_no_spns"; + internal const string net_listener_cannot_set_custom_cbt = "net_listener_cannot_set_custom_cbt"; + internal const string net_listener_cbt_not_supported = "net_listener_cbt_not_supported"; + internal const string net_listener_detach_error = "net_listener_detach_error"; + internal const string net_listener_close_urlgroup_error = "net_listener_close_urlgroup_error"; + internal const string net_tls_version = "net_tls_version"; + internal const string net_perm_target = "net_perm_target"; + internal const string net_perm_both_regex = "net_perm_both_regex"; + internal const string net_perm_none = "net_perm_none"; + internal const string net_perm_attrib_count = "net_perm_attrib_count"; + internal const string net_perm_invalid_val = "net_perm_invalid_val"; + internal const string net_perm_attrib_multi = "net_perm_attrib_multi"; + internal const string net_perm_epname = "net_perm_epname"; + internal const string net_perm_invalid_val_in_element = "net_perm_invalid_val_in_element"; + internal const string net_invalid_ip_addr = "net_invalid_ip_addr"; + internal const string dns_bad_ip_address = "dns_bad_ip_address"; + internal const string net_bad_mac_address = "net_bad_mac_address"; + internal const string net_ping = "net_ping"; + internal const string net_bad_ip_address_prefix = "net_bad_ip_address_prefix"; + internal const string net_max_ip_address_list_length_exceeded = "net_max_ip_address_list_length_exceeded"; + internal const string net_ipv4_not_installed = "net_ipv4_not_installed"; + internal const string net_ipv6_not_installed = "net_ipv6_not_installed"; + internal const string net_webclient = "net_webclient"; + internal const string net_webclient_ContentType = "net_webclient_ContentType"; + internal const string net_webclient_Multipart = "net_webclient_Multipart"; + internal const string net_webclient_no_concurrent_io_allowed = "net_webclient_no_concurrent_io_allowed"; + internal const string net_webclient_invalid_baseaddress = "net_webclient_invalid_baseaddress"; + internal const string net_container_add_cookie = "net_container_add_cookie"; + internal const string net_cookie_invalid = "net_cookie_invalid"; + internal const string net_cookie_size = "net_cookie_size"; + internal const string net_cookie_parse_header = "net_cookie_parse_header"; + internal const string net_cookie_attribute = "net_cookie_attribute"; + internal const string net_cookie_format = "net_cookie_format"; + internal const string net_cookie_exists = "net_cookie_exists"; + internal const string net_cookie_capacity_range = "net_cookie_capacity_range"; + internal const string net_set_token = "net_set_token"; + internal const string net_revert_token = "net_revert_token"; + internal const string net_ssl_io_async_context = "net_ssl_io_async_context"; + internal const string net_ssl_io_encrypt = "net_ssl_io_encrypt"; + internal const string net_ssl_io_decrypt = "net_ssl_io_decrypt"; + internal const string net_ssl_io_context_expired = "net_ssl_io_context_expired"; + internal const string net_ssl_io_handshake_start = "net_ssl_io_handshake_start"; + internal const string net_ssl_io_handshake = "net_ssl_io_handshake"; + internal const string net_ssl_io_frame = "net_ssl_io_frame"; + internal const string net_ssl_io_corrupted = "net_ssl_io_corrupted"; + internal const string net_ssl_io_cert_validation = "net_ssl_io_cert_validation"; + internal const string net_ssl_io_invalid_end_call = "net_ssl_io_invalid_end_call"; + internal const string net_ssl_io_invalid_begin_call = "net_ssl_io_invalid_begin_call"; + internal const string net_ssl_io_no_server_cert = "net_ssl_io_no_server_cert"; + internal const string net_auth_bad_client_creds = "net_auth_bad_client_creds"; + internal const string net_auth_bad_client_creds_or_target_mismatch = "net_auth_bad_client_creds_or_target_mismatch"; + internal const string net_auth_context_expectation = "net_auth_context_expectation"; + internal const string net_auth_context_expectation_remote = "net_auth_context_expectation_remote"; + internal const string net_auth_supported_impl_levels = "net_auth_supported_impl_levels"; + internal const string net_auth_no_anonymous_support = "net_auth_no_anonymous_support"; + internal const string net_auth_reauth = "net_auth_reauth"; + internal const string net_auth_noauth = "net_auth_noauth"; + internal const string net_auth_client_server = "net_auth_client_server"; + internal const string net_auth_noencryption = "net_auth_noencryption"; + internal const string net_auth_SSPI = "net_auth_SSPI"; + internal const string net_auth_failure = "net_auth_failure"; + internal const string net_auth_eof = "net_auth_eof"; + internal const string net_auth_alert = "net_auth_alert"; + internal const string net_auth_ignored_reauth = "net_auth_ignored_reauth"; + internal const string net_auth_empty_read = "net_auth_empty_read"; + internal const string net_auth_message_not_encrypted = "net_auth_message_not_encrypted"; + internal const string net_auth_must_specify_extended_protection_scheme = "net_auth_must_specify_extended_protection_scheme"; + internal const string net_frame_size = "net_frame_size"; + internal const string net_frame_read_io = "net_frame_read_io"; + internal const string net_frame_read_size = "net_frame_read_size"; + internal const string net_frame_max_size = "net_frame_max_size"; + internal const string net_jscript_load = "net_jscript_load"; + internal const string net_proxy_not_gmt = "net_proxy_not_gmt"; + internal const string net_proxy_invalid_dayofweek = "net_proxy_invalid_dayofweek"; + internal const string net_proxy_invalid_url_format = "net_proxy_invalid_url_format"; + internal const string net_param_not_string = "net_param_not_string"; + internal const string net_value_cannot_be_negative = "net_value_cannot_be_negative"; + internal const string net_invalid_offset = "net_invalid_offset"; + internal const string net_offset_plus_count = "net_offset_plus_count"; + internal const string net_cannot_be_false = "net_cannot_be_false"; + internal const string net_invalid_enum = "net_invalid_enum"; + internal const string net_listener_already = "net_listener_already"; + internal const string net_cache_shadowstream_not_writable = "net_cache_shadowstream_not_writable"; + internal const string net_cache_validator_fail = "net_cache_validator_fail"; + internal const string net_cache_access_denied = "net_cache_access_denied"; + internal const string net_cache_validator_result = "net_cache_validator_result"; + internal const string net_cache_retrieve_failure = "net_cache_retrieve_failure"; + internal const string net_cache_not_supported_body = "net_cache_not_supported_body"; + internal const string net_cache_not_supported_command = "net_cache_not_supported_command"; + internal const string net_cache_not_accept_response = "net_cache_not_accept_response"; + internal const string net_cache_method_failed = "net_cache_method_failed"; + internal const string net_cache_key_failed = "net_cache_key_failed"; + internal const string net_cache_no_stream = "net_cache_no_stream"; + internal const string net_cache_unsupported_partial_stream = "net_cache_unsupported_partial_stream"; + internal const string net_cache_not_configured = "net_cache_not_configured"; + internal const string net_cache_non_seekable_stream_not_supported = "net_cache_non_seekable_stream_not_supported"; + internal const string net_invalid_cast = "net_invalid_cast"; + internal const string net_collection_readonly = "net_collection_readonly"; + internal const string net_not_ipermission = "net_not_ipermission"; + internal const string net_no_classname = "net_no_classname"; + internal const string net_no_typename = "net_no_typename"; + internal const string net_array_too_small = "net_array_too_small"; + internal const string net_servicePointAddressNotSupportedInHostMode = "net_servicePointAddressNotSupportedInHostMode"; + internal const string net_Websockets_AlreadyOneOutstandingOperation = "net_Websockets_AlreadyOneOutstandingOperation"; + internal const string net_Websockets_WebSocketBaseFaulted = "net_Websockets_WebSocketBaseFaulted"; + internal const string net_WebSockets_NativeSendResponseHeaders = "net_WebSockets_NativeSendResponseHeaders"; + internal const string net_WebSockets_Generic = "net_WebSockets_Generic"; + internal const string net_WebSockets_NotAWebSocket_Generic = "net_WebSockets_NotAWebSocket_Generic"; + internal const string net_WebSockets_UnsupportedWebSocketVersion_Generic = "net_WebSockets_UnsupportedWebSocketVersion_Generic"; + internal const string net_WebSockets_HeaderError_Generic = "net_WebSockets_HeaderError_Generic"; + internal const string net_WebSockets_UnsupportedProtocol_Generic = "net_WebSockets_UnsupportedProtocol_Generic"; + internal const string net_WebSockets_UnsupportedPlatform = "net_WebSockets_UnsupportedPlatform"; + internal const string net_WebSockets_AcceptNotAWebSocket = "net_WebSockets_AcceptNotAWebSocket"; + internal const string net_WebSockets_AcceptUnsupportedWebSocketVersion = "net_WebSockets_AcceptUnsupportedWebSocketVersion"; + internal const string net_WebSockets_AcceptHeaderNotFound = "net_WebSockets_AcceptHeaderNotFound"; + internal const string net_WebSockets_AcceptUnsupportedProtocol = "net_WebSockets_AcceptUnsupportedProtocol"; + internal const string net_WebSockets_ClientAcceptingNoProtocols = "net_WebSockets_ClientAcceptingNoProtocols"; + internal const string net_WebSockets_ClientSecWebSocketProtocolsBlank = "net_WebSockets_ClientSecWebSocketProtocolsBlank"; + internal const string net_WebSockets_ArgumentOutOfRange_TooSmall = "net_WebSockets_ArgumentOutOfRange_TooSmall"; + internal const string net_WebSockets_ArgumentOutOfRange_InternalBuffer = "net_WebSockets_ArgumentOutOfRange_InternalBuffer"; + internal const string net_WebSockets_ArgumentOutOfRange_TooBig = "net_WebSockets_ArgumentOutOfRange_TooBig"; + internal const string net_WebSockets_InvalidState_Generic = "net_WebSockets_InvalidState_Generic"; + internal const string net_WebSockets_InvalidState_ClosedOrAborted = "net_WebSockets_InvalidState_ClosedOrAborted"; + internal const string net_WebSockets_InvalidState = "net_WebSockets_InvalidState"; + internal const string net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync = "net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync"; + internal const string net_WebSockets_InvalidMessageType = "net_WebSockets_InvalidMessageType"; + internal const string net_WebSockets_InvalidBufferType = "net_WebSockets_InvalidBufferType"; + internal const string net_WebSockets_InvalidMessageType_Generic = "net_WebSockets_InvalidMessageType_Generic"; + internal const string net_WebSockets_Argument_InvalidMessageType = "net_WebSockets_Argument_InvalidMessageType"; + internal const string net_WebSockets_ConnectionClosedPrematurely_Generic = "net_WebSockets_ConnectionClosedPrematurely_Generic"; + internal const string net_WebSockets_InvalidCharInProtocolString = "net_WebSockets_InvalidCharInProtocolString"; + internal const string net_WebSockets_InvalidEmptySubProtocol = "net_WebSockets_InvalidEmptySubProtocol"; + internal const string net_WebSockets_ReasonNotNull = "net_WebSockets_ReasonNotNull"; + internal const string net_WebSockets_InvalidCloseStatusCode = "net_WebSockets_InvalidCloseStatusCode"; + internal const string net_WebSockets_InvalidCloseStatusDescription = "net_WebSockets_InvalidCloseStatusDescription"; + internal const string net_WebSockets_Scheme = "net_WebSockets_Scheme"; + internal const string net_WebSockets_AlreadyStarted = "net_WebSockets_AlreadyStarted"; + internal const string net_WebSockets_Connect101Expected = "net_WebSockets_Connect101Expected"; + internal const string net_WebSockets_InvalidResponseHeader = "net_WebSockets_InvalidResponseHeader"; + internal const string net_WebSockets_NotConnected = "net_WebSockets_NotConnected"; + internal const string net_WebSockets_InvalidRegistration = "net_WebSockets_InvalidRegistration"; + internal const string net_WebSockets_NoDuplicateProtocol = "net_WebSockets_NoDuplicateProtocol"; + internal const string net_log_exception = "net_log_exception"; + internal const string net_log_listener_delegate_exception = "net_log_listener_delegate_exception"; + internal const string net_log_listener_unsupported_authentication_scheme = "net_log_listener_unsupported_authentication_scheme"; + internal const string net_log_listener_unmatched_authentication_scheme = "net_log_listener_unmatched_authentication_scheme"; + internal const string net_log_listener_create_valid_identity_failed = "net_log_listener_create_valid_identity_failed"; + internal const string net_log_listener_httpsys_registry_null = "net_log_listener_httpsys_registry_null"; + internal const string net_log_listener_httpsys_registry_error = "net_log_listener_httpsys_registry_error"; + internal const string net_log_listener_cant_convert_raw_path = "net_log_listener_cant_convert_raw_path"; + internal const string net_log_listener_cant_convert_percent_value = "net_log_listener_cant_convert_percent_value"; + internal const string net_log_listener_cant_convert_bytes = "net_log_listener_cant_convert_bytes"; + internal const string net_log_listener_cant_convert_to_utf8 = "net_log_listener_cant_convert_to_utf8"; + internal const string net_log_listener_cant_create_uri = "net_log_listener_cant_create_uri"; + internal const string net_log_listener_no_cbt_disabled = "net_log_listener_no_cbt_disabled"; + internal const string net_log_listener_no_cbt_http = "net_log_listener_no_cbt_http"; + internal const string net_log_listener_no_cbt_platform = "net_log_listener_no_cbt_platform"; + internal const string net_log_listener_no_cbt_trustedproxy = "net_log_listener_no_cbt_trustedproxy"; + internal const string net_log_listener_cbt = "net_log_listener_cbt"; + internal const string net_log_listener_no_spn_kerberos = "net_log_listener_no_spn_kerberos"; + internal const string net_log_listener_no_spn_disabled = "net_log_listener_no_spn_disabled"; + internal const string net_log_listener_no_spn_cbt = "net_log_listener_no_spn_cbt"; + internal const string net_log_listener_no_spn_platform = "net_log_listener_no_spn_platform"; + internal const string net_log_listener_no_spn_whensupported = "net_log_listener_no_spn_whensupported"; + internal const string net_log_listener_no_spn_loopback = "net_log_listener_no_spn_loopback"; + internal const string net_log_listener_spn = "net_log_listener_spn"; + internal const string net_log_listener_spn_passed = "net_log_listener_spn_passed"; + internal const string net_log_listener_spn_failed = "net_log_listener_spn_failed"; + internal const string net_log_listener_spn_failed_always = "net_log_listener_spn_failed_always"; + internal const string net_log_listener_spn_failed_empty = "net_log_listener_spn_failed_empty"; + internal const string net_log_listener_spn_failed_dump = "net_log_listener_spn_failed_dump"; + internal const string net_log_listener_spn_add = "net_log_listener_spn_add"; + internal const string net_log_listener_spn_not_add = "net_log_listener_spn_not_add"; + internal const string net_log_listener_spn_remove = "net_log_listener_spn_remove"; + internal const string net_log_listener_spn_not_remove = "net_log_listener_spn_not_remove"; + internal const string net_log_sspi_enumerating_security_packages = "net_log_sspi_enumerating_security_packages"; + internal const string net_log_sspi_security_package_not_found = "net_log_sspi_security_package_not_found"; + internal const string net_log_sspi_security_context_input_buffer = "net_log_sspi_security_context_input_buffer"; + internal const string net_log_sspi_security_context_input_buffers = "net_log_sspi_security_context_input_buffers"; + internal const string net_log_sspi_selected_cipher_suite = "net_log_sspi_selected_cipher_suite"; + internal const string net_log_remote_certificate = "net_log_remote_certificate"; + internal const string net_log_locating_private_key_for_certificate = "net_log_locating_private_key_for_certificate"; + internal const string net_log_cert_is_of_type_2 = "net_log_cert_is_of_type_2"; + internal const string net_log_found_cert_in_store = "net_log_found_cert_in_store"; + internal const string net_log_did_not_find_cert_in_store = "net_log_did_not_find_cert_in_store"; + internal const string net_log_open_store_failed = "net_log_open_store_failed"; + internal const string net_log_got_certificate_from_delegate = "net_log_got_certificate_from_delegate"; + internal const string net_log_no_delegate_and_have_no_client_cert = "net_log_no_delegate_and_have_no_client_cert"; + internal const string net_log_no_delegate_but_have_client_cert = "net_log_no_delegate_but_have_client_cert"; + internal const string net_log_attempting_restart_using_cert = "net_log_attempting_restart_using_cert"; + internal const string net_log_no_issuers_try_all_certs = "net_log_no_issuers_try_all_certs"; + internal const string net_log_server_issuers_look_for_matching_certs = "net_log_server_issuers_look_for_matching_certs"; + internal const string net_log_selected_cert = "net_log_selected_cert"; + internal const string net_log_n_certs_after_filtering = "net_log_n_certs_after_filtering"; + internal const string net_log_finding_matching_certs = "net_log_finding_matching_certs"; + internal const string net_log_using_cached_credential = "net_log_using_cached_credential"; + internal const string net_log_remote_cert_user_declared_valid = "net_log_remote_cert_user_declared_valid"; + internal const string net_log_remote_cert_user_declared_invalid = "net_log_remote_cert_user_declared_invalid"; + internal const string net_log_remote_cert_has_no_errors = "net_log_remote_cert_has_no_errors"; + internal const string net_log_remote_cert_has_errors = "net_log_remote_cert_has_errors"; + internal const string net_log_remote_cert_not_available = "net_log_remote_cert_not_available"; + internal const string net_log_remote_cert_name_mismatch = "net_log_remote_cert_name_mismatch"; + internal const string net_log_proxy_autodetect_script_location_parse_error = "net_log_proxy_autodetect_script_location_parse_error"; + internal const string net_log_proxy_autodetect_failed = "net_log_proxy_autodetect_failed"; + internal const string net_log_proxy_script_execution_error = "net_log_proxy_script_execution_error"; + internal const string net_log_proxy_script_download_compile_error = "net_log_proxy_script_download_compile_error"; + internal const string net_log_proxy_system_setting_update = "net_log_proxy_system_setting_update"; + internal const string net_log_proxy_update_due_to_ip_config_change = "net_log_proxy_update_due_to_ip_config_change"; + internal const string net_log_proxy_called_with_null_parameter = "net_log_proxy_called_with_null_parameter"; + internal const string net_log_proxy_called_with_invalid_parameter = "net_log_proxy_called_with_invalid_parameter"; + internal const string net_log_proxy_ras_supported = "net_log_proxy_ras_supported"; + internal const string net_log_proxy_ras_notsupported_exception = "net_log_proxy_ras_notsupported_exception"; + internal const string net_log_proxy_winhttp_cant_open_session = "net_log_proxy_winhttp_cant_open_session"; + internal const string net_log_proxy_winhttp_getproxy_failed = "net_log_proxy_winhttp_getproxy_failed"; + internal const string net_log_proxy_winhttp_timeout_error = "net_log_proxy_winhttp_timeout_error"; + internal const string net_log_digest_hash_algorithm_not_supported = "net_log_digest_hash_algorithm_not_supported"; + internal const string net_log_digest_qop_not_supported = "net_log_digest_qop_not_supported"; + internal const string net_log_digest_requires_nonce = "net_log_digest_requires_nonce"; + internal const string net_log_auth_invalid_challenge = "net_log_auth_invalid_challenge"; + internal const string net_log_unknown = "net_log_unknown"; + internal const string net_log_operation_returned_something = "net_log_operation_returned_something"; + internal const string net_log_operation_failed_with_error = "net_log_operation_failed_with_error"; + internal const string net_log_buffered_n_bytes = "net_log_buffered_n_bytes"; + internal const string net_log_method_equal = "net_log_method_equal"; + internal const string net_log_releasing_connection = "net_log_releasing_connection"; + internal const string net_log_unexpected_exception = "net_log_unexpected_exception"; + internal const string net_log_server_response_error_code = "net_log_server_response_error_code"; + internal const string net_log_resubmitting_request = "net_log_resubmitting_request"; + internal const string net_log_retrieving_localhost_exception = "net_log_retrieving_localhost_exception"; + internal const string net_log_resolved_servicepoint_may_not_be_remote_server = "net_log_resolved_servicepoint_may_not_be_remote_server"; + internal const string net_log_closed_idle = "net_log_closed_idle"; + internal const string net_log_received_status_line = "net_log_received_status_line"; + internal const string net_log_sending_headers = "net_log_sending_headers"; + internal const string net_log_received_headers = "net_log_received_headers"; + internal const string net_log_shell_expression_pattern_format_warning = "net_log_shell_expression_pattern_format_warning"; + internal const string net_log_exception_in_callback = "net_log_exception_in_callback"; + internal const string net_log_sending_command = "net_log_sending_command"; + internal const string net_log_received_response = "net_log_received_response"; + internal const string net_log_socket_connected = "net_log_socket_connected"; + internal const string net_log_socket_accepted = "net_log_socket_accepted"; + internal const string net_log_socket_not_logged_file = "net_log_socket_not_logged_file"; + internal const string net_log_socket_connect_dnsendpoint = "net_log_socket_connect_dnsendpoint"; + internal const string SSPIInvalidHandleType = "SSPIInvalidHandleType"; + + private static SR loader = null; + private ResourceManager resources; + + internal SR() + { + resources = new System.Resources.ResourceManager("System", this.GetType().Assembly); + } + + private static SR GetLoader() + { + if (loader == null) + { + SR sr = new SR(); + Interlocked.CompareExchange(ref loader, sr, null); + } + return loader; + } + + private static CultureInfo Culture + { + get { return null/*use ResourceManager default, CultureInfo.CurrentUICulture*/; } + } + + public static ResourceManager Resources + { + get + { + return GetLoader().resources; + } + } + + public static string GetString(string name, params object[] args) + { + SR sys = GetLoader(); + if (sys == null) + { + return null; + } + string res = sys.resources.GetString(name, SR.Culture); + + if (args != null && args.Length > 0) + { + for (int i = 0; i < args.Length; i++) + { + String value = args[i] as String; + if (value != null && value.Length > 1024) + { + args[i] = value.Substring(0, 1024 - 3) + "..."; + } + } + return String.Format(CultureInfo.CurrentCulture, res, args); + } + else + { + return res; + } + } + + public static string GetString(string name) + { + SR sys = GetLoader(); + if (sys == null) + { + return null; + } + return sys.resources.GetString(name, SR.Culture); + } + + public static string GetString(string name, out bool usedFallback) + { + // always false for this version of gensr + usedFallback = false; + return GetString(name); + } + + public static object GetObject(string name) + { + SR sys = GetLoader(); + if (sys == null) + { + return null; + } + return sys.resources.GetObject(name, SR.Culture); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs new file mode 100644 index 0000000000..ff7a09000b --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs @@ -0,0 +1,74 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Security.Windows +{ + using System; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.Net.Security; + using System.Runtime.InteropServices; + using System.Runtime.Versioning; + using System.Security.Authentication.ExtendedProtection; + using System.Security.Cryptography.X509Certificates; + using System.Security.Permissions; + + internal static class ValidationHelper + { + public static string ExceptionMessage(Exception exception) + { + if (exception == null) + { + return string.Empty; + } + if (exception.InnerException == null) + { + return exception.Message; + } + return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")"; + } + + public static string ToString(object objectValue) + { + if (objectValue == null) + { + return "(null)"; + } + else if (objectValue is string && ((string)objectValue).Length == 0) + { + return "(string.empty)"; + } + else if (objectValue is Exception) + { + return ExceptionMessage(objectValue as Exception); + } + else if (objectValue is IntPtr) + { + return "0x" + ((IntPtr)objectValue).ToString("x"); + } + else + { + return objectValue.ToString(); + } + } + public static string HashString(object objectValue) + { + if (objectValue == null) + { + return "(null)"; + } + else if (objectValue is string && ((string)objectValue).Length == 0) + { + return "(string.empty)"; + } + else + { + return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo); + } + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs b/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs new file mode 100644 index 0000000000..25cae8a500 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs @@ -0,0 +1,721 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Net; +using System.Security.Authentication.ExtendedProtection; +using System.Security.Permissions; +using System.Security.Principal; +using System.Text; +using System.Threading; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class NTAuthentication + { + private static readonly ContextCallback Callback = new ContextCallback(InitializeCallback); + private static ISSPIInterface SSPIAuth = new SSPIAuthType(); + + private bool _isServer; + + private SafeFreeCredentials _credentialsHandle; + private SafeDeleteContext _securityContext; + private string _spn; + private string _clientSpecifiedSpn; + + private int _tokenSize; + private ContextFlags _requestedContextFlags; + private ContextFlags _contextFlags; + private string _uniqueUserId; + + private bool _isCompleted; + private string _protocolName; + private SecSizes _sizes; + private string _lastProtocolName; + private string _package; + + private ChannelBinding _channelBinding; + + // This overload does not attmept to impersonate because the caller either did it already or the original thread context is still preserved + + internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding) + { + Initialize(isServer, package, credential, spn, requestedContextFlags, channelBinding); + } + + // This overload always uses the default credentials for the process. + + [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)] + internal NTAuthentication(bool isServer, string package, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding) + { + try + { + using (WindowsIdentity.Impersonate(IntPtr.Zero)) + { + Initialize(isServer, package, CredentialCache.DefaultNetworkCredentials, spn, requestedContextFlags, channelBinding); + } + } + catch + { + // Avoid exception filter attacks. + throw; + } + } + + // The semantic of this propoerty is "Don't call me again". + // It can be completed either with success or error + // The latest case is signalled by IsValidContext==false + internal bool IsCompleted + { + get + { + return _isCompleted; + } + } + + internal bool IsValidContext + { + get + { + return !(_securityContext == null || _securityContext.IsInvalid); + } + } + + internal string AssociatedName + { + get + { + if (!(IsValidContext && IsCompleted)) + { + throw new Win32Exception((int)SecurityStatus.InvalidHandle); + } + + string name = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext, ContextAttribute.Names) as string; + GlobalLog.Print("NTAuthentication: The context is associated with [" + name + "]"); + return name; + } + } + + internal bool IsConfidentialityFlag + { + get + { + return (_contextFlags & ContextFlags.Confidentiality) != 0; + } + } + + internal bool IsIntegrityFlag + { + get + { + return (_contextFlags & (_isServer ? ContextFlags.AcceptIntegrity : ContextFlags.InitIntegrity)) != 0; + } + } + + internal bool IsMutualAuthFlag + { + get + { + return (_contextFlags & ContextFlags.MutualAuth) != 0; + } + } + + internal bool IsDelegationFlag + { + get + { + return (_contextFlags & ContextFlags.Delegate) != 0; + } + } + + internal bool IsIdentifyFlag + { + get + { + return (_contextFlags & (_isServer ? ContextFlags.AcceptIdentify : ContextFlags.InitIdentify)) != 0; + } + } + + internal string Spn + { + get + { + return _spn; + } + } + + internal string ClientSpecifiedSpn + { + get + { + if (_clientSpecifiedSpn == null) + { + _clientSpecifiedSpn = GetClientSpecifiedSpn(); + } + return _clientSpecifiedSpn; + } + } + + // True indicates this instance is for Server and will use AcceptSecurityContext SSPI API + + internal bool IsServer + { + get + { + return _isServer; + } + } + + internal bool IsKerberos + { + get + { + if (_lastProtocolName == null) + { + _lastProtocolName = ProtocolName; + } + + return (object)_lastProtocolName == (object)NegotiationInfoClass.Kerberos; + } + } + internal bool IsNTLM + { + get + { + if (_lastProtocolName == null) + { + _lastProtocolName = ProtocolName; + } + + return (object)_lastProtocolName == (object)NegotiationInfoClass.NTLM; + } + } + + internal string Package + { + get + { + return _package; + } + } + + internal string ProtocolName + { + get + { + // NB: May return string.Empty if the auth is not done yet or failed + if (_protocolName == null) + { + NegotiationInfoClass negotiationInfo = null; + + if (IsValidContext) + { + negotiationInfo = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext, ContextAttribute.NegotiationInfo) as NegotiationInfoClass; + if (IsCompleted) + { + if (negotiationInfo != null) + { + // cache it only when it's completed + _protocolName = negotiationInfo.AuthenticationPackage; + } + } + } + return negotiationInfo == null ? string.Empty : negotiationInfo.AuthenticationPackage; + } + return _protocolName; + } + } + + internal SecSizes Sizes + { + get + { + GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::MaxDataSize|The context is not completed or invalid.", ValidationHelper.HashString(this)); + if (_sizes == null) + { + _sizes = SSPIWrapper.QueryContextAttributes( + SSPIAuth, + _securityContext, + ContextAttribute.Sizes) as SecSizes; + } + return _sizes; + } + } + + internal ChannelBinding ChannelBinding + { + get { return _channelBinding; } + } + + private static void InitializeCallback(object state) + { + InitializeCallbackContext context = (InitializeCallbackContext)state; + context.ThisPtr.Initialize(context.IsServer, context.Package, context.Credential, context.Spn, context.RequestedContextFlags, context.ChannelBinding); + } + + private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding) + { + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor() package:" + ValidationHelper.ToString(package) + " spn:" + ValidationHelper.ToString(spn) + " flags :" + requestedContextFlags.ToString()); + _tokenSize = SSPIWrapper.GetVerifyPackageInfo(SSPIAuth, package, true).MaxToken; + _isServer = isServer; + _spn = spn; + _securityContext = null; + _requestedContextFlags = requestedContextFlags; + _package = package; + _channelBinding = channelBinding; + + GlobalLog.Print("Peer SPN-> '" + _spn + "'"); + + // check if we're using DefaultCredentials + + if (credential == CredentialCache.DefaultNetworkCredentials) + { + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using DefaultCredentials"); + _credentialsHandle = SSPIWrapper.AcquireDefaultCredential( + SSPIAuth, + package, + (_isServer ? CredentialUse.Inbound : CredentialUse.Outbound)); + _uniqueUserId = "/S"; // save off for unique connection marking ONLY used by HTTP client + } + else if (ComNetOS.IsWin7orLater) + { + unsafe + { + SafeSspiAuthDataHandle authData = null; + try + { + SecurityStatus result = UnsafeNclNativeMethods.SspiHelper.SspiEncodeStringsAsAuthIdentity( + credential.UserName/*InternalGetUserName()*/, credential.Domain/*InternalGetDomain()*/, + credential.Password/*InternalGetPassword()*/, out authData); + + if (result != SecurityStatus.OK) + { + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "SspiEncodeStringsAsAuthIdentity()", String.Format(CultureInfo.CurrentCulture, "0x{0:X}", (int)result))); + } + throw new Win32Exception((int)result); + } + + _credentialsHandle = SSPIWrapper.AcquireCredentialsHandle(SSPIAuth, + package, (_isServer ? CredentialUse.Inbound : CredentialUse.Outbound), ref authData); + } + finally + { + if (authData != null) + { + authData.Dispose(); + } + } + } + } + else + { + // we're not using DefaultCredentials, we need a + // AuthIdentity struct to contain credentials + // SECREVIEW: + // we'll save username/domain in temp strings, to avoid decrypting multiple times. + // password is only used once + + string username = credential.UserName; // InternalGetUserName(); + + string domain = credential.Domain; // InternalGetDomain(); + // ATTN: + // NetworkCredential class does not differentiate between null and "" but SSPI packages treat these cases differently + // For NTLM we want to keep "" for Wdigest.Dll we should use null. + AuthIdentity authIdentity = new AuthIdentity(username, credential.Password/*InternalGetPassword()*/, (object)package == (object)NegotiationInfoClass.WDigest && (domain == null || domain.Length == 0) ? null : domain); + + _uniqueUserId = domain + "/" + username + "/U"; // save off for unique connection marking ONLY used by HTTP client + + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using authIdentity:" + authIdentity.ToString()); + + _credentialsHandle = SSPIWrapper.AcquireCredentialsHandle( + SSPIAuth, + package, + (_isServer ? CredentialUse.Inbound : CredentialUse.Outbound), + ref authIdentity); + } + } + + // This will return an client token when conducted authentication on server side' + // This token can be used ofr impersanation + // We use it to create a WindowsIdentity and hand it out to the server app. + internal SafeCloseHandle GetContextToken(out SecurityStatus status) + { + GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", ValidationHelper.HashString(this)); + GlobalLog.Assert(IsServer, "NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", ValidationHelper.HashString(this)); + + if (!IsValidContext) + { + throw new Win32Exception((int)SecurityStatus.InvalidHandle); + } + + SafeCloseHandle token = null; + status = (SecurityStatus)SSPIWrapper.QuerySecurityContextToken( + SSPIAuth, + _securityContext, + out token); + + return token; + } + + internal SafeCloseHandle GetContextToken() + { + SecurityStatus status; + SafeCloseHandle token = GetContextToken(out status); + if (status != SecurityStatus.OK) + { + throw new Win32Exception((int)status); + } + return token; + } + + internal void CloseContext() + { + if (_securityContext != null && !_securityContext.IsClosed) + { + _securityContext.Dispose(); + } + } + + // NTAuth::GetOutgoingBlob() + // Created: 12-01-1999: L.M. + // Description: + // Accepts an incoming binary security blob and returns + // an outgoing binary security blob + internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatus statusCode) + { + GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes"); + + List list = new List(2); + + if (incomingBlob != null) + { + list.Add(new SecurityBuffer(incomingBlob, BufferType.Token)); + } + if (_channelBinding != null) + { + list.Add(new SecurityBuffer(_channelBinding)); + } + + SecurityBuffer[] inSecurityBufferArray = null; + if (list.Count > 0) + { + inSecurityBufferArray = list.ToArray(); + } + + SecurityBuffer outSecurityBuffer = new SecurityBuffer(_tokenSize, BufferType.Token); + + bool firstTime = _securityContext == null; + try + { + if (!_isServer) + { + // client session + statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext( + SSPIAuth, + _credentialsHandle, + ref _securityContext, + _spn, + _requestedContextFlags, + Endianness.Network, + inSecurityBufferArray, + outSecurityBuffer, + ref _contextFlags); + + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); + + if (statusCode == SecurityStatus.CompleteNeeded) + { + SecurityBuffer[] inSecurityBuffers = new SecurityBuffer[1]; + inSecurityBuffers[0] = outSecurityBuffer; + + statusCode = (SecurityStatus)SSPIWrapper.CompleteAuthToken( + SSPIAuth, + ref _securityContext, + inSecurityBuffers); + + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); + outSecurityBuffer.token = null; + } + } + else + { + // server session + statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext( + SSPIAuth, + _credentialsHandle, + ref _securityContext, + _requestedContextFlags, + Endianness.Network, + inSecurityBufferArray, + outSecurityBuffer, + ref _contextFlags); + + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); + } + } + finally + { + // Assuming the ISC or ASC has referenced the credential on the first successful call, + // we want to decrement the effective ref count by "disposing" it. + // The real dispose will happen when the security context is closed. + // Note if the first call was not successfull the handle is physically destroyed here + + if (firstTime && _credentialsHandle != null) + { + _credentialsHandle.Dispose(); + } + } + + if (((int)statusCode & unchecked((int)0x80000000)) != 0) + { + CloseContext(); + _isCompleted = true; + if (throwOnError) + { + Win32Exception exception = new Win32Exception((int)statusCode); + GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception); + throw exception; + } + GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); + return null; + } + else if (firstTime && _credentialsHandle != null) + { + // cache until it is pushed out by newly incoming handles + SSPIHandleCache.CacheCredential(_credentialsHandle); + } + + // the return value from SSPI will tell us correctly if the + // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm + // we also have to consider the case in which SSPI formed a new context, in this case we're done as well. + if (statusCode == SecurityStatus.OK) + { + // we're sucessfully done + GlobalLog.Assert(statusCode == SecurityStatus.OK, "NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", ValidationHelper.HashString(this), (int)statusCode, statusCode, ValidationHelper.HashString(_securityContext), ValidationHelper.ToString(_securityContext)); + _isCompleted = true; + } + else + { + // we need to continue + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(_securityContext) + "::Handle:" + ValidationHelper.ToString(_securityContext) + "]"); + } + // GlobalLog.Print("out token = " + outSecurityBuffer.ToString()); + // GlobalLog.Dump(outSecurityBuffer.token); + GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString()); + return outSecurityBuffer.token; + } + + // for Server side (IIS 6.0) see: \\netindex\Sources\inetsrv\iis\iisrearc\iisplus\ulw3\digestprovider.cxx + // for Client side (HTTP.SYS) see: \\netindex\Sources\net\http\sys\ucauth.c + internal string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, string requestedUri, string realm, bool isClientPreAuth, bool throwOnError, out SecurityStatus statusCode) + { + GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", incomingBlob); + + // second time call with 3 incoming buffers to select HTTP client. + // we should get back a SecurityStatus.OK and a non null outgoingBlob. + SecurityBuffer[] inSecurityBuffers = null; + SecurityBuffer outSecurityBuffer = new SecurityBuffer(_tokenSize, isClientPreAuth ? BufferType.Parameters : BufferType.Token); + + bool firstTime = _securityContext == null; + try + { + if (!_isServer) + { + // client session + + if (!isClientPreAuth) + { + if (incomingBlob != null) + { + List list = new List(5); + + list.Add(new SecurityBuffer(HeaderEncoding.GetBytes(incomingBlob), BufferType.Token)); + list.Add(new SecurityBuffer(HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters)); + list.Add(new SecurityBuffer(null, BufferType.Parameters)); + list.Add(new SecurityBuffer(Encoding.Unicode.GetBytes(_spn), BufferType.TargetHost)); + + if (_channelBinding != null) + { + list.Add(new SecurityBuffer(_channelBinding)); + } + + inSecurityBuffers = list.ToArray(); + } + + statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext( + SSPIAuth, + _credentialsHandle, + ref _securityContext, + requestedUri, // this must match the Uri in the HTTP status line for the current request + _requestedContextFlags, + Endianness.Network, + inSecurityBuffers, + outSecurityBuffer, + ref _contextFlags); + + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); + } + else + { +#if WDIGEST_PREAUTH + inSecurityBuffers = new SecurityBuffer[] { + new SecurityBuffer(null, BufferType.Token), + new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters), + new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters), + new SecurityBuffer(null, BufferType.Parameters), + outSecurityBuffer, + }; + + statusCode = (SecurityStatus) SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, m_SecurityContext, inSecurityBuffers, 0); + + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.MakeSignature() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); +#else + statusCode = SecurityStatus.OK; + GlobalLog.Assert("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob()", "Invalid code path."); +#endif + } + } + else + { + // server session + List list = new List(6); + + list.Add(incomingBlob == null ? new SecurityBuffer(0, BufferType.Token) : new SecurityBuffer(HeaderEncoding.GetBytes(incomingBlob), BufferType.Token)); + list.Add(requestMethod == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters)); + list.Add(requestedUri == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters)); + list.Add(new SecurityBuffer(0, BufferType.Parameters)); + list.Add(realm == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(Encoding.Unicode.GetBytes(realm), BufferType.Parameters)); + + if (_channelBinding != null) + { + list.Add(new SecurityBuffer(_channelBinding)); + } + + inSecurityBuffers = list.ToArray(); + + statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext( + SSPIAuth, + _credentialsHandle, + ref _securityContext, + _requestedContextFlags, + Endianness.Network, + inSecurityBuffers, + outSecurityBuffer, + ref _contextFlags); + + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); + + if (statusCode == SecurityStatus.CompleteNeeded) + { + inSecurityBuffers[4] = outSecurityBuffer; + + statusCode = (SecurityStatus)SSPIWrapper.CompleteAuthToken( + SSPIAuth, + ref _securityContext, + inSecurityBuffers); + + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); + + outSecurityBuffer.token = null; + } + } + } + finally + { + // Assuming the ISC or ASC has referenced the credential on the first successful call, + // we want to decrement the effective ref count by "disposing" it. + // The real dispose will happen when the security context is closed. + // Note if the first call was not successfull the handle is physically destroyed here + + if (firstTime && _credentialsHandle != null) + { + _credentialsHandle.Dispose(); + } + } + + if (((int)statusCode & unchecked((int)0x80000000)) != 0) + { + CloseContext(); + if (throwOnError) + { + Win32Exception exception = new Win32Exception((int)statusCode); + GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "Win32Exception:" + exception); + throw exception; + } + GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "null statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); + return null; + } + else if (firstTime && _credentialsHandle != null) + { + // cache until it is pushed out by newly incoming handles + SSPIHandleCache.CacheCredential(_credentialsHandle); + } + + // the return value from SSPI will tell us correctly if the + // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm + if (statusCode == SecurityStatus.OK) + { + // we're done, cleanup + _isCompleted = true; + } + else + { + // we need to continue + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() need continue statusCode:[0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(_securityContext) + "::Handle:" + ValidationHelper.ToString(_securityContext) + "]"); + } + GlobalLog.Print("out token = " + outSecurityBuffer.ToString()); + GlobalLog.Dump(outSecurityBuffer.token); + GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() IsCompleted:" + IsCompleted.ToString()); + + byte[] decodedOutgoingBlob = outSecurityBuffer.token; + string outgoingBlob = null; + if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) + { + outgoingBlob = HeaderEncoding.GetString(decodedOutgoingBlob, 0, outSecurityBuffer.size); + } + GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", outgoingBlob); + return outgoingBlob; + } + + private string GetClientSpecifiedSpn() + { + GlobalLog.Assert(IsValidContext && IsCompleted, "NTAuthentication: Trying to get the client SPN before handshaking is done!"); + + string spn = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext, + ContextAttribute.ClientSpecifiedSpn) as string; + + GlobalLog.Print("NTAuthentication: The client specified SPN is [" + spn + "]"); + return spn; + } + + private class InitializeCallbackContext + { + internal readonly NTAuthentication ThisPtr; + internal readonly bool IsServer; + internal readonly string Package; + internal readonly NetworkCredential Credential; + internal readonly string Spn; + internal readonly ContextFlags RequestedContextFlags; + internal readonly ChannelBinding ChannelBinding; + + internal InitializeCallbackContext(NTAuthentication thisPtr, bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding) + { + this.ThisPtr = thisPtr; + this.IsServer = isServer; + this.Package = package; + this.Credential = credential; + this.Spn = spn; + this.RequestedContextFlags = requestedContextFlags; + this.ChannelBinding = channelBinding; + } + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs new file mode 100644 index 0000000000..dcd73516a9 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct AuthIdentity + { + // see SEC_WINNT_AUTH_IDENTITY_W + internal string UserName; + internal int UserNameLength; + internal string Domain; + internal int DomainLength; + internal string Password; + internal int PasswordLength; + internal int Flags; + + internal AuthIdentity(string userName, string password, string domain) + { + UserName = userName; + UserNameLength = userName == null ? 0 : userName.Length; + Password = password; + PasswordLength = password == null ? 0 : password.Length; + Domain = domain; + DomainLength = domain == null ? 0 : domain.Length; + // Flags are 2 for Unicode and 1 for ANSI. We use 2 on NT and 1 on Win9x. + Flags = 2; + } + + public override string ToString() + { + return ValidationHelper.ToString(Domain) + "\\" + ValidationHelper.ToString(UserName); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs new file mode 100644 index 0000000000..21ef3b735d --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs @@ -0,0 +1,124 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; + +namespace Microsoft.AspNet.Security.Windows +{ + // #define ISC_REQ_DELEGATE 0x00000001 + // #define ISC_REQ_MUTUAL_AUTH 0x00000002 + // #define ISC_REQ_REPLAY_DETECT 0x00000004 + // #define ISC_REQ_SEQUENCE_DETECT 0x00000008 + // #define ISC_REQ_CONFIDENTIALITY 0x00000010 + // #define ISC_REQ_USE_SESSION_KEY 0x00000020 + // #define ISC_REQ_PROMPT_FOR_CREDS 0x00000040 + // #define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080 + // #define ISC_REQ_ALLOCATE_MEMORY 0x00000100 + // #define ISC_REQ_USE_DCE_STYLE 0x00000200 + // #define ISC_REQ_DATAGRAM 0x00000400 + // #define ISC_REQ_CONNECTION 0x00000800 + // #define ISC_REQ_CALL_LEVEL 0x00001000 + // #define ISC_REQ_FRAGMENT_SUPPLIED 0x00002000 + // #define ISC_REQ_EXTENDED_ERROR 0x00004000 + // #define ISC_REQ_STREAM 0x00008000 + // #define ISC_REQ_INTEGRITY 0x00010000 + // #define ISC_REQ_IDENTIFY 0x00020000 + // #define ISC_REQ_NULL_SESSION 0x00040000 + // #define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000 + // #define ISC_REQ_RESERVED1 0x00100000 + // #define ISC_REQ_FRAGMENT_TO_FIT 0x00200000 + // #define ISC_REQ_HTTP 0x10000000 + // Win7 SP1 + + // #define ISC_REQ_UNVERIFIED_TARGET_NAME 0x20000000 + + // #define ASC_REQ_DELEGATE 0x00000001 + // #define ASC_REQ_MUTUAL_AUTH 0x00000002 + // #define ASC_REQ_REPLAY_DETECT 0x00000004 + // #define ASC_REQ_SEQUENCE_DETECT 0x00000008 + // #define ASC_REQ_CONFIDENTIALITY 0x00000010 + // #define ASC_REQ_USE_SESSION_KEY 0x00000020 + // #define ASC_REQ_ALLOCATE_MEMORY 0x00000100 + // #define ASC_REQ_USE_DCE_STYLE 0x00000200 + // #define ASC_REQ_DATAGRAM 0x00000400 + // #define ASC_REQ_CONNECTION 0x00000800 + // #define ASC_REQ_CALL_LEVEL 0x00001000 + // #define ASC_REQ_EXTENDED_ERROR 0x00008000 + // #define ASC_REQ_STREAM 0x00010000 + // #define ASC_REQ_INTEGRITY 0x00020000 + // #define ASC_REQ_LICENSING 0x00040000 + // #define ASC_REQ_IDENTIFY 0x00080000 + // #define ASC_REQ_ALLOW_NULL_SESSION 0x00100000 + // #define ASC_REQ_ALLOW_NON_USER_LOGONS 0x00200000 + // #define ASC_REQ_ALLOW_CONTEXT_REPLAY 0x00400000 + // #define ASC_REQ_FRAGMENT_TO_FIT 0x00800000 + // #define ASC_REQ_FRAGMENT_SUPPLIED 0x00002000 + // #define ASC_REQ_NO_TOKEN 0x01000000 + // #define ASC_REQ_HTTP 0x10000000 + + [Flags] + internal enum ContextFlags + { + Zero = 0, + // The server in the transport application can + // build new security contexts impersonating the + // client that will be accepted by other servers + // as the client's contexts. + Delegate = 0x00000001, + // The communicating parties must authenticate + // their identities to each other. Without MutualAuth, + // the client authenticates its identity to the server. + // With MutualAuth, the server also must authenticate + // its identity to the client. + MutualAuth = 0x00000002, + // The security package detects replayed packets and + // notifies the caller if a packet has been replayed. + // The use of this flag implies all of the conditions + // specified by the Integrity flag. + ReplayDetect = 0x00000004, + // The context must be allowed to detect out-of-order + // delivery of packets later through the message support + // functions. Use of this flag implies all of the + // conditions specified by the Integrity flag. + SequenceDetect = 0x00000008, + // The context must protect data while in transit. + // Confidentiality is supported for NTLM with Microsoft + // Windows NT version 4.0, SP4 and later and with the + // Kerberos protocol in Microsoft Windows 2000 and later. + Confidentiality = 0x00000010, + UseSessionKey = 0x00000020, + AllocateMemory = 0x00000100, + + // Connection semantics must be used. + Connection = 0x00000800, + + // Client applications requiring extended error messages specify the + // ISC_REQ_EXTENDED_ERROR flag when calling the InitializeSecurityContext + // Server applications requiring extended error messages set + // the ASC_REQ_EXTENDED_ERROR flag when calling AcceptSecurityContext. + InitExtendedError = 0x00004000, + AcceptExtendedError = 0x00008000, + // A transport application requests stream semantics + // by setting the ISC_REQ_STREAM and ASC_REQ_STREAM + // flags in the calls to the InitializeSecurityContext + // and AcceptSecurityContext functions + InitStream = 0x00008000, + AcceptStream = 0x00010000, + // Buffer integrity can be verified; however, replayed + // and out-of-sequence messages will not be detected + InitIntegrity = 0x00010000, // ISC_REQ_INTEGRITY + AcceptIntegrity = 0x00020000, // ASC_REQ_INTEGRITY + + InitManualCredValidation = 0x00080000, // ISC_REQ_MANUAL_CRED_VALIDATION + InitUseSuppliedCreds = 0x00000080, // ISC_REQ_USE_SUPPLIED_CREDS + InitIdentify = 0x00020000, // ISC_REQ_IDENTIFY + AcceptIdentify = 0x00080000, // ASC_REQ_IDENTIFY + + ProxyBindings = 0x04000000, // ASC_REQ_PROXY_BINDINGS + AllowMissingBindings = 0x10000000, // ASC_REQ_ALLOW_MISSING_BINDINGS + + UnverifiedTargetName = 0x20000000, // ISC_REQ_UNVERIFIED_TARGET_NAME + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs new file mode 100644 index 0000000000..1ac0a7d055 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + // used to define the interface for security to use. + internal interface ISSPIInterface + { + SecurityPackageInfoClass[] SecurityPackages { get; set; } + int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray); + int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref AuthIdentity authdata, out SafeFreeCredentials outCredential); + int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential); + int AcquireDefaultCredential(string moduleName, CredentialUse usage, out SafeFreeCredentials outCredential); + int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref SecureCredential authdata, out SafeFreeCredentials outCredential); + int AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, ContextFlags inFlags, + Endianness endianness, SecurityBuffer outputBuffer, ref ContextFlags outFlags); + int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, ContextFlags inFlags, + Endianness endianness, SecurityBuffer outputBuffer, ref ContextFlags outFlags); + int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, + Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlags outFlags); + int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, + Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags); + int EncryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber); + int DecryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber); + int MakeSignature(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber); + int VerifySignature(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber); + + int QueryContextChannelBinding(SafeDeleteContext phContext, ContextAttribute attribute, out SafeFreeContextBufferChannelBinding refHandle); + int QueryContextAttributes(SafeDeleteContext phContext, ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle); + int SetContextAttributes(SafeDeleteContext phContext, ContextAttribute attribute, byte[] buffer); + int QuerySecurityContextToken(SafeDeleteContext phContext, out SafeCloseHandle phToken); + int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers); + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs new file mode 100644 index 0000000000..e7951e2969 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs @@ -0,0 +1,302 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class SSPIAuthType : ISSPIInterface + { + private static volatile SecurityPackageInfoClass[] _securityPackages; + + public SecurityPackageInfoClass[] SecurityPackages + { + get + { + return _securityPackages; + } + set + { + _securityPackages = value; + } + } + + public int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray) + { + GlobalLog.Print("SSPIAuthType::EnumerateSecurityPackages()"); + return SafeFreeContextBuffer.EnumeratePackages(out pkgnum, out pkgArray); + } + + public int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref AuthIdentity authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcquireDefaultCredential(string moduleName, CredentialUse usage, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireDefaultCredential(moduleName, usage, out outCredential); + } + + public int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref SecureCredential authdata, out SafeFreeCredentials outCredential) + { + return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); + } + + public int AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, ContextFlags inFlags, Endianness endianness, SecurityBuffer outputBuffer, ref ContextFlags outFlags) + { + return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags); + } + + public int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, ContextFlags inFlags, Endianness endianness, SecurityBuffer outputBuffer, ref ContextFlags outFlags) + { + return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags); + } + + public int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlags outFlags) + { + return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags); + } + + public int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags) + { + return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags); + } + + public int EncryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + int status = (int)SecurityStatus.InvalidHandle; + bool b = false; + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + context.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + context.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + status = UnsafeNclNativeMethods.NativeNTSSPI.EncryptMessage(ref context._handle, 0, inputOutput, sequenceNumber); + context.DangerousRelease(); + } + } + return status; + } + + public unsafe int DecryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + int status = (int)SecurityStatus.InvalidHandle; + bool b = false; + uint qop = 0; + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + context.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + context.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + status = UnsafeNclNativeMethods.NativeNTSSPI.DecryptMessage(ref context._handle, inputOutput, sequenceNumber, &qop); + context.DangerousRelease(); + } + } + + const uint SECQOP_WRAP_NO_ENCRYPT = 0x80000001; + if (status == 0 && qop == SECQOP_WRAP_NO_ENCRYPT) + { + GlobalLog.Assert("NativeNTSSPI.DecryptMessage", "Expected qop = 0, returned value = " + qop.ToString("x", CultureInfo.InvariantCulture)); + throw new InvalidOperationException(SR.GetString(SR.net_auth_message_not_encrypted)); + } + + return status; + } + + public int MakeSignature(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + int status = (int)SecurityStatus.InvalidHandle; + bool b = false; + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + context.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + context.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + const uint SECQOP_WRAP_NO_ENCRYPT = 0x80000001; + status = UnsafeNclNativeMethods.NativeNTSSPI.EncryptMessage(ref context._handle, SECQOP_WRAP_NO_ENCRYPT, inputOutput, sequenceNumber); + context.DangerousRelease(); + } + } + return status; + } + + public unsafe int VerifySignature(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) + { + int status = (int)SecurityStatus.InvalidHandle; + bool b = false; + + uint qop = 0; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + context.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + context.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + status = UnsafeNclNativeMethods.NativeNTSSPI.DecryptMessage(ref context._handle, inputOutput, sequenceNumber, &qop); + context.DangerousRelease(); + } + } + + return status; + } + + public int QueryContextChannelBinding(SafeDeleteContext context, ContextAttribute attribute, out SafeFreeContextBufferChannelBinding binding) + { + // Querying an auth SSP for a CBT doesn't make sense + binding = null; + throw new NotSupportedException(); + } + + public unsafe int QueryContextAttributes(SafeDeleteContext context, ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle) + { + refHandle = null; + if (handleType != null) + { + if (handleType == typeof(SafeFreeContextBuffer)) + { + refHandle = SafeFreeContextBuffer.CreateEmptyHandle(); + } + else if (handleType == typeof(SafeFreeCertContext)) + { + refHandle = new SafeFreeCertContext(); + } + else + { + throw new ArgumentException(SR.GetString(SR.SSPIInvalidHandleType, handleType.FullName), "handleType"); + } + } + + fixed (byte* bufferPtr = buffer) + { + return SafeFreeContextBuffer.QueryContextAttributes(context, attribute, bufferPtr, refHandle); + } + } + + public int SetContextAttributes(SafeDeleteContext context, ContextAttribute attribute, byte[] buffer) + { + throw new NotImplementedException(); + } + + public int QuerySecurityContextToken(SafeDeleteContext phContext, out SafeCloseHandle phToken) + { + return GetSecurityContextToken(phContext, out phToken); + } + + public int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers) + { + return SafeDeleteContext.CompleteAuthToken(ref refContext, inputBuffers); + } + + private static int GetSecurityContextToken(SafeDeleteContext phContext, out SafeCloseHandle safeHandle) + { + int status = (int)SecurityStatus.InvalidHandle; + bool b = false; + safeHandle = null; + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + phContext.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + phContext.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + status = UnsafeNclNativeMethods.SafeNetHandles.QuerySecurityContextToken(ref phContext._handle, out safeHandle); + phContext.DangerousRelease(); + } + } + + return status; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs new file mode 100644 index 0000000000..52728d3825 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs @@ -0,0 +1,36 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct SSPIHandle + { + private IntPtr HandleHi; + private IntPtr HandleLo; + + public bool IsZero + { + get { return HandleHi == IntPtr.Zero && HandleLo == IntPtr.Zero; } + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal void SetToInvalid() + { + HandleHi = IntPtr.Zero; + HandleLo = IntPtr.Zero; + } + + public override string ToString() + { + return HandleHi.ToString("x") + ":" + HandleLo.ToString("x"); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs new file mode 100644 index 0000000000..e30c1ab434 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +/* +Abstract: + The file implements trivial SSPI credential caching mechanism based on lru list +*/ +using System; +using System.Threading; + +namespace Microsoft.AspNet.Security.Windows +{ + // Implements delayed SSPI handle release, like a finalizable object though the handles are kept alive until being pushed out + // by the newly incoming ones. + internal static class SSPIHandleCache + { + private const int MaxCacheSize = 0x1F; // must a (power of 2) - 1 + private static SafeCredentialReference[] _cacheSlots = new SafeCredentialReference[MaxCacheSize + 1]; + private static int _current = -1; + + internal static void CacheCredential(SafeFreeCredentials newHandle) + { + try + { + SafeCredentialReference newRef = SafeCredentialReference.CreateReference(newHandle); + if (newRef == null) + { + return; + } + unchecked + { + int index = Interlocked.Increment(ref _current) & MaxCacheSize; + newRef = Interlocked.Exchange(ref _cacheSlots[index], newRef); + } + if (newRef != null) + { + newRef.Dispose(); + } + } + catch (Exception e) + { + GlobalLog.Assert("SSPIHandlCache", "Attempted to throw: " + e.ToString()); + } + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs new file mode 100644 index 0000000000..4c04e704b2 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs @@ -0,0 +1,462 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + // From Schannel.h + + [StructLayout(LayoutKind.Sequential)] + internal struct NegotiationInfo + { + // see SecPkgContext_NegotiationInfoW in + + // [MarshalAs(UnmanagedType.LPStruct)] internal SecurityPackageInfo PackageInfo; + internal IntPtr PackageInfo; + internal uint NegotiationState; + internal static readonly int Size = Marshal.SizeOf(typeof(NegotiationInfo)); + internal static readonly int NegotiationStateOffest = (int)Marshal.OffsetOf(typeof(NegotiationInfo), "NegotiationState"); + } + + // we keep it simple since we use this only to know if NTLM or + // Kerberos are used in the context of a Negotiate handshake + + [StructLayout(LayoutKind.Sequential)] + internal struct SecurityPackageInfo + { + // see SecPkgInfoW in + internal int Capabilities; + internal short Version; + internal short RPCID; + internal int MaxToken; + internal IntPtr Name; + internal IntPtr Comment; + + internal static readonly int Size = Marshal.SizeOf(typeof(SecurityPackageInfo)); + internal static readonly int NameOffest = (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Name"); + } + + [StructLayout(LayoutKind.Sequential)] + internal struct Bindings + { + // see SecPkgContext_Bindings in + internal int BindingsLength; + internal IntPtr pBindings; + } + + internal static class SSPIWrapper + { + internal static SecurityPackageInfoClass[] EnumerateSecurityPackages(ISSPIInterface secModule) + { + GlobalLog.Enter("EnumerateSecurityPackages"); + if (secModule.SecurityPackages == null) + { + lock (secModule) + { + if (secModule.SecurityPackages == null) + { + int moduleCount = 0; + SafeFreeContextBuffer arrayBaseHandle = null; + try + { + int errorCode = secModule.EnumerateSecurityPackages(out moduleCount, out arrayBaseHandle); + GlobalLog.Print("SSPIWrapper::arrayBase: " + (arrayBaseHandle.DangerousGetHandle().ToString("x"))); + if (errorCode != 0) + { + throw new Win32Exception(errorCode); + } + SecurityPackageInfoClass[] securityPackages = new SecurityPackageInfoClass[moduleCount]; + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_sspi_enumerating_security_packages)); + } + int i; + for (i = 0; i < moduleCount; i++) + { + securityPackages[i] = new SecurityPackageInfoClass(arrayBaseHandle, i); + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, " " + securityPackages[i].Name); + } + } + secModule.SecurityPackages = securityPackages; + } + finally + { + if (arrayBaseHandle != null) + { + arrayBaseHandle.Dispose(); + } + } + } + } + } + GlobalLog.Leave("EnumerateSecurityPackages"); + return secModule.SecurityPackages; + } + + internal static SecurityPackageInfoClass GetVerifyPackageInfo(ISSPIInterface secModule, string packageName, bool throwIfMissing) + { + SecurityPackageInfoClass[] supportedSecurityPackages = EnumerateSecurityPackages(secModule); + if (supportedSecurityPackages != null) + { + for (int i = 0; i < supportedSecurityPackages.Length; i++) + { + if (string.Compare(supportedSecurityPackages[i].Name, packageName, StringComparison.OrdinalIgnoreCase) == 0) + { + return supportedSecurityPackages[i]; + } + } + } + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_sspi_security_package_not_found, packageName)); + } + + // error + if (throwIfMissing) + { + throw new NotSupportedException(SR.GetString(SR.net_securitypackagesupport)); + } + + return null; + } + + public static SafeFreeCredentials AcquireDefaultCredential(ISSPIInterface secModule, string package, CredentialUse intent) + { + GlobalLog.Print("SSPIWrapper::AcquireDefaultCredential(): using " + package); + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcquireDefaultCredential(" + + "package = " + package + ", " + + "intent = " + intent + ")"); + } + + SafeFreeCredentials outCredential = null; + int errorCode = secModule.AcquireDefaultCredential(package, intent, out outCredential); + + if (errorCode != 0) + { +#if TRAVE + GlobalLog.Print("SSPIWrapper::AcquireDefaultCredential(): error " + SecureChannel.MapSecurityStatus((uint)errorCode)); +#endif + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "AcquireDefaultCredential()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); + } + throw new Win32Exception(errorCode); + } + return outCredential; + } + + public static SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface secModule, string package, CredentialUse intent, ref AuthIdentity authdata) + { + GlobalLog.Print("SSPIWrapper::AcquireCredentialsHandle#2(): using " + package); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcquireCredentialsHandle(" + + "package = " + package + ", " + + "intent = " + intent + ", " + + "authdata = " + authdata + ")"); + } + + SafeFreeCredentials credentialsHandle = null; + int errorCode = secModule.AcquireCredentialsHandle(package, + intent, + ref authdata, + out credentialsHandle); + + if (errorCode != 0) + { + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "AcquireCredentialsHandle()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); + } + throw new Win32Exception(errorCode); + } + return credentialsHandle; + } + + public static SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface secModule, string package, CredentialUse intent, ref SafeSspiAuthDataHandle authdata) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcquireCredentialsHandle(" + + "package = " + package + ", " + + "intent = " + intent + ", " + + "authdata = " + authdata + ")"); + } + + SafeFreeCredentials credentialsHandle = null; + int errorCode = secModule.AcquireCredentialsHandle(package, intent, ref authdata, out credentialsHandle); + + if (errorCode != 0) + { + if (Logging.On) + { + Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "AcquireCredentialsHandle()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); + } + throw new Win32Exception(errorCode); + } + return credentialsHandle; + } + + internal static int InitializeSecurityContext(ISSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, Endianness datarep, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "InitializeSecurityContext(" + + "credential = " + credential.ToString() + ", " + + "context = " + ValidationHelper.ToString(context) + ", " + + "targetName = " + targetName + ", " + + "inFlags = " + inFlags + ")"); + } + + int errorCode = secModule.InitializeSecurityContext(credential, ref context, targetName, inFlags, datarep, inputBuffers, outputBuffer, ref outFlags); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_sspi_security_context_input_buffers, "InitializeSecurityContext", (inputBuffers == null ? 0 : inputBuffers.Length), outputBuffer.size, (SecurityStatus)errorCode)); + } + + return errorCode; + } + + internal static int AcceptSecurityContext(ISSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, ContextFlags inFlags, Endianness datarep, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, + "AcceptSecurityContext(" + + "credential = " + credential.ToString() + ", " + + "context = " + ValidationHelper.ToString(context) + ", " + + "inFlags = " + inFlags + ")"); + } + + int errorCode = secModule.AcceptSecurityContext(credential, ref context, inputBuffers, inFlags, datarep, outputBuffer, ref outFlags); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_sspi_security_context_input_buffers, "AcceptSecurityContext", (inputBuffers == null ? 0 : inputBuffers.Length), outputBuffer.size, (SecurityStatus)errorCode)); + } + + return errorCode; + } + + internal static int CompleteAuthToken(ISSPIInterface secModule, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers) + { + int errorCode = secModule.CompleteAuthToken(ref context, inputBuffers); + + if (Logging.On) + { + Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_operation_returned_something, "CompleteAuthToken()", (SecurityStatus)errorCode)); + } + + return errorCode; + } + + public static int QuerySecurityContextToken(ISSPIInterface secModule, SafeDeleteContext context, out SafeCloseHandle token) + { + return secModule.QuerySecurityContextToken(context, out token); + } + + public static SafeFreeContextBufferChannelBinding QueryContextChannelBinding(ISSPIInterface secModule, SafeDeleteContext securityContext, ContextAttribute contextAttribute) + { + GlobalLog.Enter("QueryContextChannelBinding", contextAttribute.ToString()); + + SafeFreeContextBufferChannelBinding result; + int errorCode = secModule.QueryContextChannelBinding(securityContext, contextAttribute, out result); + if (errorCode != 0) + { + GlobalLog.Leave("QueryContextChannelBinding", "ERROR = " + ErrorDescription(errorCode)); + return null; + } + + GlobalLog.Leave("QueryContextChannelBinding", ValidationHelper.HashString(result)); + return result; + } + + public static object QueryContextAttributes(ISSPIInterface secModule, SafeDeleteContext securityContext, ContextAttribute contextAttribute) + { + int errorCode; + return QueryContextAttributes(secModule, securityContext, contextAttribute, out errorCode); + } + + public static object QueryContextAttributes(ISSPIInterface secModule, SafeDeleteContext securityContext, ContextAttribute contextAttribute, out int errorCode) + { + GlobalLog.Enter("QueryContextAttributes", contextAttribute.ToString()); + + int nativeBlockSize = IntPtr.Size; + Type handleType = null; + + switch (contextAttribute) + { + case ContextAttribute.Sizes: + nativeBlockSize = SecSizes.SizeOf; + break; + case ContextAttribute.StreamSizes: + nativeBlockSize = StreamSizes.SizeOf; + break; + + case ContextAttribute.Names: + handleType = typeof(SafeFreeContextBuffer); + break; + + case ContextAttribute.PackageInfo: + handleType = typeof(SafeFreeContextBuffer); + break; + + case ContextAttribute.NegotiationInfo: + handleType = typeof(SafeFreeContextBuffer); + nativeBlockSize = Marshal.SizeOf(typeof(NegotiationInfo)); + break; + + case ContextAttribute.ClientSpecifiedSpn: + handleType = typeof(SafeFreeContextBuffer); + break; + + case ContextAttribute.RemoteCertificate: + handleType = typeof(SafeFreeCertContext); + break; + + case ContextAttribute.LocalCertificate: + handleType = typeof(SafeFreeCertContext); + break; + + case ContextAttribute.IssuerListInfoEx: + nativeBlockSize = Marshal.SizeOf(typeof(IssuerListInfoEx)); + handleType = typeof(SafeFreeContextBuffer); + break; + + case ContextAttribute.ConnectionInfo: + nativeBlockSize = Marshal.SizeOf(typeof(SslConnectionInfo)); + break; + + default: + throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "ContextAttribute"), "contextAttribute"); + } + + SafeHandle SspiHandle = null; + object attribute = null; + + try + { + byte[] nativeBuffer = new byte[nativeBlockSize]; + errorCode = secModule.QueryContextAttributes(securityContext, contextAttribute, nativeBuffer, handleType, out SspiHandle); + if (errorCode != 0) + { + GlobalLog.Leave("Win32:QueryContextAttributes", "ERROR = " + ErrorDescription(errorCode)); + return null; + } + + switch (contextAttribute) + { + case ContextAttribute.Sizes: + attribute = new SecSizes(nativeBuffer); + break; + + case ContextAttribute.StreamSizes: + attribute = new StreamSizes(nativeBuffer); + break; + + case ContextAttribute.Names: + attribute = Marshal.PtrToStringUni(SspiHandle.DangerousGetHandle()); + break; + + case ContextAttribute.PackageInfo: + attribute = new SecurityPackageInfoClass(SspiHandle, 0); + break; + + case ContextAttribute.NegotiationInfo: + unsafe + { + fixed (void* ptr = nativeBuffer) + { + attribute = new NegotiationInfoClass(SspiHandle, Marshal.ReadInt32(new IntPtr(ptr), NegotiationInfo.NegotiationStateOffest)); + } + } + break; + + case ContextAttribute.ClientSpecifiedSpn: + attribute = Marshal.PtrToStringUni(SspiHandle.DangerousGetHandle()); + break; + + case ContextAttribute.LocalCertificate: + goto case ContextAttribute.RemoteCertificate; + case ContextAttribute.RemoteCertificate: + attribute = SspiHandle; + SspiHandle = null; + break; + + case ContextAttribute.IssuerListInfoEx: + attribute = new IssuerListInfoEx(SspiHandle, nativeBuffer); + SspiHandle = null; + break; + + case ContextAttribute.ConnectionInfo: + attribute = new SslConnectionInfo(nativeBuffer); + break; + default: + // will return null + break; + } + } + finally + { + if (SspiHandle != null) + { + SspiHandle.Dispose(); + } + } + GlobalLog.Leave("QueryContextAttributes", ValidationHelper.ToString(attribute)); + return attribute; + } + + public static string ErrorDescription(int errorCode) + { + if (errorCode == -1) + { + return "An exception when invoking Win32 API"; + } + switch ((SecurityStatus)errorCode) + { + case SecurityStatus.InvalidHandle: + return "Invalid handle"; + case SecurityStatus.InvalidToken: + return "Invalid token"; + case SecurityStatus.ContinueNeeded: + return "Continue needed"; + case SecurityStatus.IncompleteMessage: + return "Message incomplete"; + case SecurityStatus.WrongPrincipal: + return "Wrong principal"; + case SecurityStatus.TargetUnknown: + return "Target unknown"; + case SecurityStatus.PackageNotFound: + return "Package not found"; + case SecurityStatus.BufferNotEnough: + return "Buffer not enough"; + case SecurityStatus.MessageAltered: + return "Message altered"; + case SecurityStatus.UntrustedRoot: + return "Untrusted root"; + default: + return "0x" + errorCode.ToString("x", NumberFormatInfo.InvariantInfo); + } + } + } // class SSPIWrapper +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs new file mode 100644 index 0000000000..1b720b1ad6 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.ConstrainedExecution; +using System.Security; +using System.Threading; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Security.Windows +{ + [SuppressUnmanagedCodeSecurity] + internal sealed class SafeCloseHandle : CriticalHandleZeroOrMinusOneIsInvalid + { + private int _disposed; + + private SafeCloseHandle() + : base() + { + } + + internal IntPtr DangerousGetHandle() + { + return handle; + } + + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + if (Interlocked.Increment(ref _disposed) == 1) + { + return UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(handle); + } + } + return true; + } + + // This method will bypass refCount check done by VM + // Means it will force handle release if has a valid value + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal void Abort() + { + ReleaseHandle(); + SetHandleAsInvalid(); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs new file mode 100644 index 0000000000..a0d29a1b61 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs @@ -0,0 +1,69 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.CompilerServices; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Security.Windows +{ + internal sealed class SafeCredentialReference : CriticalHandleMinusOneIsInvalid + { + // Static cache will return the target handle if found the reference in the table. + internal SafeFreeCredentials _Target; + + private SafeCredentialReference(SafeFreeCredentials target) + : base() + { + // Bumps up the refcount on Target to signify that target handle is statically cached so + // its dispose should be postponed + bool b = false; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + target.DangerousAddRef(ref b); + } + catch + { + if (b) + { + target.DangerousRelease(); + b = false; + } + } + finally + { + if (b) + { + _Target = target; + SetHandle(new IntPtr(0)); // make this handle valid + } + } + } + + internal static SafeCredentialReference CreateReference(SafeFreeCredentials target) + { + SafeCredentialReference result = new SafeCredentialReference(target); + if (result.IsInvalid) + { + return null; + } + + return result; + } + + protected override bool ReleaseHandle() + { + SafeFreeCredentials target = _Target; + if (target != null) + { + target.DangerousRelease(); + } + _Target = null; + return true; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs new file mode 100644 index 0000000000..a356f2b3ef --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs @@ -0,0 +1,707 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + internal sealed class SafeDeleteContext : SafeHandle + { + private const string DummyStr = " "; + private static readonly byte[] DummyBytes = new byte[] { 0 }; + + // ATN: _handle is internal since it is used on PInvokes by other wrapper methods. + // However all such wrappers MUST manually and reliably adjust refCounter of SafeDeleteContext handle. + + internal SSPIHandle _handle; + + private SafeFreeCredentials _effectiveCredential; + + private SafeDeleteContext() + : base(IntPtr.Zero, true) + { + _handle = new SSPIHandle(); + } + + public override bool IsInvalid + { + get + { + return IsClosed || _handle.IsZero; + } + } + + public override string ToString() + { + return _handle.ToString(); + } + + //------------------------------------------------------------------- + internal static unsafe int InitializeSecurityContext(ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, + string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, + SecurityBuffer outSecBuffer, ref ContextFlags outFlags) + { + GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::InitializeSecurityContext()|outSecBuffer != null"); + GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::InitializeSecurityContext()|inSecBuffer == null || inSecBuffers == null"); + + if (inCredentials == null) + { + throw new ArgumentNullException("inCredentials"); + } + + SecurityBufferDescriptor inSecurityBufferDescriptor = null; + if (inSecBuffer != null) + { + inSecurityBufferDescriptor = new SecurityBufferDescriptor(1); + } + else if (inSecBuffers != null) + { + inSecurityBufferDescriptor = new SecurityBufferDescriptor(inSecBuffers.Length); + } + SecurityBufferDescriptor outSecurityBufferDescriptor = new SecurityBufferDescriptor(1); + + // actually this is returned in outFlags + bool isSspiAllocated = (inFlags & ContextFlags.AllocateMemory) != 0 ? true : false; + + int errorCode = -1; + + SSPIHandle contextHandle = new SSPIHandle(); + if (refContext != null) + { + contextHandle = refContext._handle; + } + + // these are pinned user byte arrays passed along with SecurityBuffers + GCHandle[] pinnedInBytes = null; + GCHandle pinnedOutBytes = new GCHandle(); + // optional output buffer that may need to be freed + SafeFreeContextBuffer outFreeContextBuffer = null; + try + { + pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); + SecurityBufferStruct[] inUnmanagedBuffer = new SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; + fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) + { + if (inSecurityBufferDescriptor != null) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers + inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; + pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; + SecurityBuffer securityBuffer; + for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) + { + securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; + if (securityBuffer != null) + { + // Copy the SecurityBuffer content into unmanaged place holder + inUnmanagedBuffer[index].count = securityBuffer.size; + inUnmanagedBuffer[index].type = securityBuffer.type; + + // use the unmanaged token if it's not null; otherwise use the managed buffer + if (securityBuffer.unmanagedToken != null) + { + inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); + } + else if (securityBuffer.token == null || securityBuffer.token.Length == 0) + { + inUnmanagedBuffer[index].token = IntPtr.Zero; + } + else + { + pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); + inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); + } + } + } + } + + SecurityBufferStruct[] outUnmanagedBuffer = new SecurityBufferStruct[1]; + fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers + outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; + outUnmanagedBuffer[0].count = outSecBuffer.size; + outUnmanagedBuffer[0].type = outSecBuffer.type; + if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) + { + outUnmanagedBuffer[0].token = IntPtr.Zero; + } + else + { + outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); + } + if (isSspiAllocated) + { + outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); + } + + if (refContext == null || refContext.IsInvalid) + { + refContext = new SafeDeleteContext(); + } + + if (targetName == null || targetName.Length == 0) + { + targetName = DummyStr; + } + + fixed (char* namePtr = targetName) + { + errorCode = MustRunInitializeSecurityContext( + ref inCredentials, + contextHandle.IsZero ? null : &contextHandle, + (byte*)(((object)targetName == (object)DummyStr) ? null : namePtr), + inFlags, + endianness, + inSecurityBufferDescriptor, + refContext, + outSecurityBufferDescriptor, + ref outFlags, + outFreeContextBuffer); + } + + GlobalLog.Print("SafeDeleteContext:InitializeSecurityContext Marshalling OUT buffer"); + // Get unmanaged buffer with index 0 as the only one passed into PInvoke + outSecBuffer.size = outUnmanagedBuffer[0].count; + outSecBuffer.type = outUnmanagedBuffer[0].type; + if (outSecBuffer.size > 0) + { + outSecBuffer.token = new byte[outSecBuffer.size]; + Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); + } + else + { + outSecBuffer.token = null; + } + } + } + } + finally + { + if (pinnedInBytes != null) + { + for (int index = 0; index < pinnedInBytes.Length; index++) + { + if (pinnedInBytes[index].IsAllocated) + { + pinnedInBytes[index].Free(); + } + } + } + if (pinnedOutBytes.IsAllocated) + { + pinnedOutBytes.Free(); + } + + if (outFreeContextBuffer != null) + { + outFreeContextBuffer.Dispose(); + } + } + + GlobalLog.Leave("SafeDeleteContext::InitializeSecurityContext() unmanaged InitializeSecurityContext()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + ValidationHelper.ToString(refContext)); + + return errorCode; + } + + // After PINvoke call the method will fix the handleTemplate.handle with the returned value. + // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. + // + // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system. + + private static unsafe int MustRunInitializeSecurityContext( + ref SafeFreeCredentials inCredentials, + void* inContextPtr, + byte* targetName, + ContextFlags inFlags, + Endianness endianness, + SecurityBufferDescriptor inputBuffer, + SafeDeleteContext outContext, + SecurityBufferDescriptor outputBuffer, + ref ContextFlags attributes, + SafeFreeContextBuffer handleTemplate) + { + int errorCode = (int)SecurityStatus.InvalidHandle; + bool b1 = false; + bool b2 = false; + + // Run the body of this method as a non-interruptible block. + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + inCredentials.DangerousAddRef(ref b1); + outContext.DangerousAddRef(ref b2); + } + catch (Exception e) + { + if (b1) + { + inCredentials.DangerousRelease(); + b1 = false; + } + if (b2) + { + outContext.DangerousRelease(); + b2 = false; + } + + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + SSPIHandle credentialHandle = inCredentials._handle; + long timeStamp; + + if (!b1) + { + // caller should retry + inCredentials = null; + } + else if (b1 && b2) + { + errorCode = UnsafeNclNativeMethods.SafeNetHandles.InitializeSecurityContextW( + ref credentialHandle, + inContextPtr, + targetName, + inFlags, + 0, + endianness, + inputBuffer, + 0, + ref outContext._handle, + outputBuffer, + ref attributes, + out timeStamp); + + // When a credential handle is first associated with the context we keep credential + // ref count bumped up to ensure ordered finalization. + // If the credential handle has been changed we de-ref the old one and associate the + // context with the new cred handle but only if the call was successful. + if (outContext._effectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) + { + // Disassociate the previous credential handle + if (outContext._effectiveCredential != null) + { + outContext._effectiveCredential.DangerousRelease(); + } + outContext._effectiveCredential = inCredentials; + } + else + { + inCredentials.DangerousRelease(); + } + + outContext.DangerousRelease(); + + // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. + if (handleTemplate != null) + { + handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); // ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes + if (handleTemplate.IsInvalid) + { + handleTemplate.SetHandleAsInvalid(); + } + } + } + + if (inContextPtr == null && (errorCode & 0x80000000) != 0) + { + // an error on the first call, need to set the out handle to invalid value + outContext._handle.SetToInvalid(); + } + } + + return errorCode; + } + + //------------------------------------------------------------------- + internal static unsafe int AcceptSecurityContext(ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, + ContextFlags inFlags, Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, + ref ContextFlags outFlags) + { + GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null"); + GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null"); + + if (inCredentials == null) + { + throw new ArgumentNullException("inCredentials"); + } + + SecurityBufferDescriptor inSecurityBufferDescriptor = null; + if (inSecBuffer != null) + { + inSecurityBufferDescriptor = new SecurityBufferDescriptor(1); + } + else if (inSecBuffers != null) + { + inSecurityBufferDescriptor = new SecurityBufferDescriptor(inSecBuffers.Length); + } + SecurityBufferDescriptor outSecurityBufferDescriptor = new SecurityBufferDescriptor(1); + + // actually this is returned in outFlags + bool isSspiAllocated = (inFlags & ContextFlags.AllocateMemory) != 0 ? true : false; + + int errorCode = -1; + + SSPIHandle contextHandle = new SSPIHandle(); + if (refContext != null) + { + contextHandle = refContext._handle; + } + + // these are pinned user byte arrays passed along with SecurityBuffers + GCHandle[] pinnedInBytes = null; + GCHandle pinnedOutBytes = new GCHandle(); + // optional output buffer that may need to be freed + SafeFreeContextBuffer outFreeContextBuffer = null; + try + { + pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); + SecurityBufferStruct[] inUnmanagedBuffer = new SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; + fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) + { + if (inSecurityBufferDescriptor != null) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers + inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; + pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; + SecurityBuffer securityBuffer; + for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) + { + securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; + if (securityBuffer != null) + { + // Copy the SecurityBuffer content into unmanaged place holder + inUnmanagedBuffer[index].count = securityBuffer.size; + inUnmanagedBuffer[index].type = securityBuffer.type; + + // use the unmanaged token if it's not null; otherwise use the managed buffer + if (securityBuffer.unmanagedToken != null) + { + inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); + } + else if (securityBuffer.token == null || securityBuffer.token.Length == 0) + { + inUnmanagedBuffer[index].token = IntPtr.Zero; + } + else + { + pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); + inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); + } + } + } + } + SecurityBufferStruct[] outUnmanagedBuffer = new SecurityBufferStruct[1]; + fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers + outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; + // Copy the SecurityBuffer content into unmanaged place holder + outUnmanagedBuffer[0].count = outSecBuffer.size; + outUnmanagedBuffer[0].type = outSecBuffer.type; + + if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) + { + outUnmanagedBuffer[0].token = IntPtr.Zero; + } + else + { + outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); + } + if (isSspiAllocated) + { + outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); + } + + if (refContext == null || refContext.IsInvalid) + { + refContext = new SafeDeleteContext(); + } + + errorCode = MustRunAcceptSecurityContext( + ref inCredentials, + contextHandle.IsZero ? null : &contextHandle, + inSecurityBufferDescriptor, + inFlags, + endianness, + refContext, + outSecurityBufferDescriptor, + ref outFlags, + outFreeContextBuffer); + + GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext Marshalling OUT buffer"); + // Get unmanaged buffer with index 0 as the only one passed into PInvoke + outSecBuffer.size = outUnmanagedBuffer[0].count; + outSecBuffer.type = outUnmanagedBuffer[0].type; + if (outSecBuffer.size > 0) + { + outSecBuffer.token = new byte[outSecBuffer.size]; + Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); + } + else + { + outSecBuffer.token = null; + } + } + } + } + finally + { + if (pinnedInBytes != null) + { + for (int index = 0; index < pinnedInBytes.Length; index++) + { + if (pinnedInBytes[index].IsAllocated) + { + pinnedInBytes[index].Free(); + } + } + } + + if (pinnedOutBytes.IsAllocated) + { + pinnedOutBytes.Free(); + } + + if (outFreeContextBuffer != null) + { + outFreeContextBuffer.Dispose(); + } + } + + GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + ValidationHelper.ToString(refContext)); + + return errorCode; + } + + // After PINvoke call the method will fix the handleTemplate.handle with the returned value. + // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. + // + // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system. + + private static unsafe int MustRunAcceptSecurityContext( + ref SafeFreeCredentials inCredentials, + void* inContextPtr, + SecurityBufferDescriptor inputBuffer, + ContextFlags inFlags, + Endianness endianness, + SafeDeleteContext outContext, + SecurityBufferDescriptor outputBuffer, + ref ContextFlags outFlags, + SafeFreeContextBuffer handleTemplate) + { + int errorCode = (int)SecurityStatus.InvalidHandle; + bool b1 = false; + bool b2 = false; + + // Run the body of this method as a non-interruptible block. + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + inCredentials.DangerousAddRef(ref b1); + outContext.DangerousAddRef(ref b2); + } + catch (Exception e) + { + if (b1) + { + inCredentials.DangerousRelease(); + b1 = false; + } + if (b2) + { + outContext.DangerousRelease(); + b2 = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + SSPIHandle credentialHandle = inCredentials._handle; + long timeStamp; + + if (!b1) + { + // caller should retry + inCredentials = null; + } + else if (b1 && b2) + { + errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcceptSecurityContext( + ref credentialHandle, + inContextPtr, + inputBuffer, + inFlags, + endianness, + ref outContext._handle, + outputBuffer, + ref outFlags, + out timeStamp); + + // When a credential handle is first associated with the context we keep credential + // ref count bumped up to ensure ordered finalization. + // If the credential handle has been changed we de-ref the old one and associate the + // context with the new cred handle but only if the call was successful. + if (outContext._effectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) + { + // Disassociate the previous credential handle + if (outContext._effectiveCredential != null) + { + outContext._effectiveCredential.DangerousRelease(); + } + outContext._effectiveCredential = inCredentials; + } + else + { + inCredentials.DangerousRelease(); + } + + outContext.DangerousRelease(); + + // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. + if (handleTemplate != null) + { + handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); // ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes + if (handleTemplate.IsInvalid) + { + handleTemplate.SetHandleAsInvalid(); + } + } + } + + if (inContextPtr == null && (errorCode & 0x80000000) != 0) + { + // an error on the first call, need to set the out handle to invalid value + outContext._handle.SetToInvalid(); + } + } + + return errorCode; + } + + internal static unsafe int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inSecBuffers) + { + GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken"); + GlobalLog.Print(" refContext = " + ValidationHelper.ToString(refContext)); + GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null"); + SecurityBufferDescriptor inSecurityBufferDescriptor = new SecurityBufferDescriptor(inSecBuffers.Length); + + int errorCode = (int)SecurityStatus.InvalidHandle; + + // these are pinned user byte arrays passed along with SecurityBuffers + GCHandle[] pinnedInBytes = null; + + SecurityBufferStruct[] inUnmanagedBuffer = new SecurityBufferStruct[inSecurityBufferDescriptor.Count]; + fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) + { + // Fix Descriptor pointer that points to unmanaged SecurityBuffers + inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; + pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; + SecurityBuffer securityBuffer; + for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) + { + securityBuffer = inSecBuffers[index]; + if (securityBuffer != null) + { + inUnmanagedBuffer[index].count = securityBuffer.size; + inUnmanagedBuffer[index].type = securityBuffer.type; + + // use the unmanaged token if it's not null; otherwise use the managed buffer + if (securityBuffer.unmanagedToken != null) + { + inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); + } + else if (securityBuffer.token == null || securityBuffer.token.Length == 0) + { + inUnmanagedBuffer[index].token = IntPtr.Zero; + } + else + { + pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); + inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); + } + } + } + + SSPIHandle contextHandle = new SSPIHandle(); + if (refContext != null) + { + contextHandle = refContext._handle; + } + try + { + if (refContext == null || refContext.IsInvalid) + { + refContext = new SafeDeleteContext(); + } + + bool b = false; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + refContext.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + refContext.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + errorCode = UnsafeNclNativeMethods.SafeNetHandles.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor); + refContext.DangerousRelease(); + } + } + } + finally + { + if (pinnedInBytes != null) + { + for (int index = 0; index < pinnedInBytes.Length; index++) + { + if (pinnedInBytes[index].IsAllocated) + { + pinnedInBytes[index].Free(); + } + } + } + } + } + + GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + ValidationHelper.ToString(refContext)); + + return errorCode; + } + + protected override bool ReleaseHandle() + { + if (this._effectiveCredential != null) + { + this._effectiveCredential.DangerousRelease(); + } + + return UnsafeNclNativeMethods.SafeNetHandles.DeleteSecurityContext(ref _handle) == 0; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs new file mode 100644 index 0000000000..20f85f5010 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs @@ -0,0 +1,35 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.ConstrainedExecution; +using System.Security; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Security.Windows +{ + [SuppressUnmanagedCodeSecurity] + internal sealed class SafeFreeCertContext : SafeHandleZeroOrMinusOneIsInvalid + { + internal SafeFreeCertContext() + : base(true) + { + } + + // This must be ONLY called from this file within a CER. + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal unsafe void Set(IntPtr value) + { + this.handle = value; + } + + protected override bool ReleaseHandle() + { + UnsafeNclNativeMethods.SafeNetHandles.CertFreeCertificateContext(handle); + return true; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs new file mode 100644 index 0000000000..db31e3018a --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs @@ -0,0 +1,148 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Security; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Security.Windows +{ + [SuppressUnmanagedCodeSecurity] + internal sealed class SafeFreeContextBuffer : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeFreeContextBuffer() + : base(true) + { + } + + // This must be ONLY called from this file and in the context of a CER + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal unsafe void Set(IntPtr value) + { + this.handle = value; + } + + internal static int EnumeratePackages(out int pkgnum, out SafeFreeContextBuffer pkgArray) + { + int res = -1; + res = UnsafeNclNativeMethods.SafeNetHandles.EnumerateSecurityPackagesW(out pkgnum, out pkgArray); + if (res != 0 && pkgArray != null) + { + pkgArray.SetHandleAsInvalid(); + } + return res; + } + + internal static SafeFreeContextBuffer CreateEmptyHandle() + { + return new SafeFreeContextBuffer(); + } + + // After PINvoke call the method will fix the refHandle.handle with the returned value. + // The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned. + // + // This method switches between three non-interruptible helper methods. (This method can't be both non-interruptible and + // reference imports from all three DLLs - doing so would cause all three DLLs to try to be bound to.) + + public static unsafe int QueryContextAttributes(SafeDeleteContext phContext, ContextAttribute contextAttribute, byte* buffer, SafeHandle refHandle) + { + int status = (int)SecurityStatus.InvalidHandle; + bool b = false; + + // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit + // one of the following methods. So run within a CER non-interruptible block. + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + phContext.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + phContext.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + status = UnsafeNclNativeMethods.SafeNetHandles.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); + phContext.DangerousRelease(); + } + + if (status == 0 && refHandle != null) + { + if (refHandle is SafeFreeContextBuffer) + { + ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); + } + else + { + ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); + } + } + + if (status != 0 && refHandle != null) + { + refHandle.SetHandleAsInvalid(); + } + } + + return status; + } + + public static int SetContextAttributes(SafeDeleteContext phContext, ContextAttribute contextAttribute, byte[] buffer) + { + int status = (int)SecurityStatus.InvalidHandle; + bool b = false; + + // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing + // to jit one of the following methods. So run within a CER non-interruptible block. + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + phContext.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + phContext.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + status = UnsafeNclNativeMethods.SafeNetHandles.SetContextAttributesW( + ref phContext._handle, contextAttribute, buffer, buffer.Length); + phContext.DangerousRelease(); + } + } + + return status; + } + + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SafeNetHandles.FreeContextBuffer(handle) == 0; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs new file mode 100644 index 0000000000..344ef38a59 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs @@ -0,0 +1,89 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +using System.Security; +using System.Security.Authentication.ExtendedProtection; + +namespace Microsoft.AspNet.Security.Windows +{ + [SuppressUnmanagedCodeSecurity] + internal sealed class SafeFreeContextBufferChannelBinding : ChannelBinding + { + private int size; + + public override int Size + { + get { return size; } + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal unsafe void Set(IntPtr value) + { + this.handle = value; + } + + internal static SafeFreeContextBufferChannelBinding CreateEmptyHandle() + { + return new SafeFreeContextBufferChannelBinding(); + } + + public static unsafe int QueryContextChannelBinding(SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, + SafeFreeContextBufferChannelBinding refHandle) + { + int status = (int)SecurityStatus.InvalidHandle; + bool b = false; + + // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit + // one of the following methods. So run within a CER non-interruptible block. + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + phContext.DangerousAddRef(ref b); + } + catch (Exception e) + { + if (b) + { + phContext.DangerousRelease(); + b = false; + } + if (!(e is ObjectDisposedException)) + { + throw; + } + } + finally + { + if (b) + { + status = UnsafeNclNativeMethods.SafeNetHandles.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); + phContext.DangerousRelease(); + } + + if (status == 0 && refHandle != null) + { + refHandle.Set((*buffer).pBindings); + refHandle.size = (*buffer).BindingsLength; + } + + if (status != 0 && refHandle != null) + { + refHandle.SetHandleAsInvalid(); + } + } + + return status; + } + + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SafeNetHandles.FreeContextBuffer(handle) == 0; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs new file mode 100644 index 0000000000..0b42913028 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs @@ -0,0 +1,199 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + internal sealed class SafeFreeCredentials : SafeHandle + { + internal SSPIHandle _handle; // should be always used as by ref in PINvokes parameters + + private SafeFreeCredentials() + : base(IntPtr.Zero, true) + { + _handle = new SSPIHandle(); + } + + public override bool IsInvalid + { + get { return IsClosed || _handle.IsZero; } + } + + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SafeNetHandles.FreeCredentialsHandle(ref _handle) == 0; + } + + public static unsafe int AcquireCredentialsHandle(string package, CredentialUse intent, ref AuthIdentity authdata, + out SafeFreeCredentials outCredential) + { + GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#1(" + + package + ", " + + intent + ", " + + authdata + ")"); + + int errorCode = -1; + long timeStamp; + + outCredential = new SafeFreeCredentials(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + } + finally + { + errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcquireCredentialsHandleW( + null, + package, + (int)intent, + null, + ref authdata, + null, + null, + ref outCredential._handle, + out timeStamp); + } + + if (errorCode != 0) + { + outCredential.SetHandleAsInvalid(); + } + return errorCode; + } + + public static unsafe int AcquireDefaultCredential(string package, CredentialUse intent, out SafeFreeCredentials outCredential) + { + GlobalLog.Print("SafeFreeCredentials::AcquireDefaultCredential(" + + package + ", " + + intent + ")"); + + int errorCode = -1; + long timeStamp; + + outCredential = new SafeFreeCredentials(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + } + finally + { + errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcquireCredentialsHandleW( + null, + package, + (int)intent, + null, + IntPtr.Zero, + null, + null, + ref outCredential._handle, + out timeStamp); + } + + if (errorCode != 0) + { + outCredential.SetHandleAsInvalid(); + } + return errorCode; + } + + // This overload is only called on Win7+ where SspiEncodeStringsAsAuthIdentity() was used to + // create the authData blob. + public static unsafe int AcquireCredentialsHandle( + string package, + CredentialUse intent, + ref SafeSspiAuthDataHandle authdata, + out SafeFreeCredentials outCredential) + { + int errorCode = -1; + long timeStamp; + + outCredential = new SafeFreeCredentials(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + } + finally + { + errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcquireCredentialsHandleW( + null, + package, + (int)intent, + null, + authdata, + null, + null, + ref outCredential._handle, + out timeStamp); + } + + if (errorCode != 0) + { + outCredential.SetHandleAsInvalid(); + } + return errorCode; + } + + public static unsafe int AcquireCredentialsHandle(string package, CredentialUse intent, ref SecureCredential authdata, + out SafeFreeCredentials outCredential) + { + GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#2(" + + package + ", " + + intent + ", " + + authdata + ")"); + + int errorCode = -1; + long timeStamp; + + // If there is a certificate, wrap it into an array. + // Not threadsafe. + IntPtr copiedPtr = authdata.certContextArray; + try + { + IntPtr certArrayPtr = new IntPtr(&copiedPtr); + if (copiedPtr != IntPtr.Zero) + { + authdata.certContextArray = certArrayPtr; + } + + outCredential = new SafeFreeCredentials(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + } + finally + { + errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcquireCredentialsHandleW( + null, + package, + (int)intent, + null, + ref authdata, + null, + null, + ref outCredential._handle, + out timeStamp); + } + } + finally + { + authdata.certContextArray = copiedPtr; + } + + if (errorCode != 0) + { + outCredential.SetHandleAsInvalid(); + } + return errorCode; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs new file mode 100644 index 0000000000..30437854d7 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs @@ -0,0 +1,48 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Security; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Security.Windows +{ + [SuppressUnmanagedCodeSecurity] + internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid + { + private const int LmemFixed = 0; + private const int NULL = 0; + + // This returned handle cannot be modified by the application. + public static SafeLocalFree Zero = new SafeLocalFree(false); + + private SafeLocalFree() + : base(true) + { + } + + private SafeLocalFree(bool ownsHandle) + : base(ownsHandle) + { + } + + public static SafeLocalFree LocalAlloc(int cb) + { + SafeLocalFree result = UnsafeNclNativeMethods.SafeNetHandles.LocalAlloc(LmemFixed, (UIntPtr)cb); + if (result.IsInvalid) + { + result.SetHandleAsInvalid(); + throw new OutOfMemoryException(); + } + return result; + } + + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs new file mode 100644 index 0000000000..e02c75aaba --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Security.Windows +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.ConstrainedExecution; + using System.Runtime.InteropServices; + using System.Security; + using System.Security.Authentication.ExtendedProtection; + using System.Threading; + using Microsoft.Win32.SafeHandles; + + [SuppressUnmanagedCodeSecurity] + internal sealed class SafeSspiAuthDataHandle : SafeHandleZeroOrMinusOneIsInvalid + { + public SafeSspiAuthDataHandle() + : base(true) + { + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SspiHelper.SspiFreeAuthIdentity(handle) == SecurityStatus.OK; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs new file mode 100644 index 0000000000..eb48aa1d3f --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs @@ -0,0 +1,41 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; + +namespace Microsoft.AspNet.Security.Windows +{ + // From Schannel.h + [Flags] + internal enum SchProtocols + { + Zero = 0, + PctClient = 0x00000002, + PctServer = 0x00000001, + Pct = (PctClient | PctServer), + Ssl2Client = 0x00000008, + Ssl2Server = 0x00000004, + Ssl2 = (Ssl2Client | Ssl2Server), + Ssl3Client = 0x00000020, + Ssl3Server = 0x00000010, + Ssl3 = (Ssl3Client | Ssl3Server), + Tls10Client = 0x00000080, + Tls10Server = 0x00000040, + Tls10 = (Tls10Client | Tls10Server), + Tls11Client = 0x00000200, + Tls11Server = 0x00000100, + Tls11 = (Tls11Client | Tls11Server), + Tls12Client = 0x00000800, + Tls12Server = 0x00000400, + Tls12 = (Tls12Client | Tls12Server), + Ssl3Tls = (Ssl3 | Tls10), + UniClient = unchecked((int)0x80000000), + UniServer = 0x40000000, + Unified = (UniClient | UniServer), + ClientMask = (PctClient | Ssl2Client | Ssl3Client | Tls10Client | Tls11Client | Tls12Client | UniClient), + ServerMask = (PctServer | Ssl2Server | Ssl3Server | Tls10Server | Tls11Server | Tls12Server | UniServer) + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs new file mode 100644 index 0000000000..0f1bb3e7a3 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs @@ -0,0 +1,44 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Security.Windows +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Globalization; + using System.Runtime.InteropServices; + + [StructLayout(LayoutKind.Sequential)] + internal class SecSizes + { + public readonly int MaxToken; + public readonly int MaxSignature; + public readonly int BlockSize; + public readonly int SecurityTrailer; + + internal unsafe SecSizes(byte[] memory) + { + fixed (void* voidPtr = memory) + { + IntPtr unmanagedAddress = new IntPtr(voidPtr); + try + { + MaxToken = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress)); + MaxSignature = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 4)); + BlockSize = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 8)); + SecurityTrailer = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 12)); + } + catch (OverflowException) + { + GlobalLog.Assert(false, "SecSizes::.ctor", "Negative size."); + throw; + } + } + } + public static readonly int SizeOf = Marshal.SizeOf(typeof(SecSizes)); + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs new file mode 100644 index 0000000000..069223dd4f --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs @@ -0,0 +1,56 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Security.Authentication.ExtendedProtection; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class SecurityBuffer + { + public int size; + public BufferType type; + public byte[] token; + public SafeHandle unmanagedToken; + public int offset; + + public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) + { + GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range. [" + offset + "]"); + GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range. [" + size + "]"); + + this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length); + this.size = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset); + this.type = tokentype; + this.token = size == 0 ? null : data; + } + + public SecurityBuffer(byte[] data, BufferType tokentype) + { + this.size = data == null ? 0 : data.Length; + this.type = tokentype; + this.token = size == 0 ? null : data; + } + + public SecurityBuffer(int size, BufferType tokentype) + { + GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range. [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]"); + + this.size = size; + this.type = tokentype; + this.token = size == 0 ? null : new byte[size]; + } + + public SecurityBuffer(ChannelBinding binding) + { + this.size = (binding == null ? 0 : binding.Size); + this.type = BufferType.ChannelBindings; + this.unmanagedToken = binding; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs new file mode 100644 index 0000000000..138f12b2bd --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs @@ -0,0 +1,33 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + [StructLayout(LayoutKind.Sequential)] + internal unsafe class SecurityBufferDescriptor + { + /* + typedef struct _SecBufferDesc { + ULONG ulVersion; + ULONG cBuffers; + PSecBuffer pBuffers; + } SecBufferDesc, * PSecBufferDesc; + */ + public readonly int Version; + public readonly int Count; + public void* UnmanagedPointer; + + public SecurityBufferDescriptor(int count) + { + Version = 0; + Count = count; + UnmanagedPointer = null; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs new file mode 100644 index 0000000000..df19cf7e37 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs @@ -0,0 +1,80 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class SecurityPackageInfoClass + { + private int _capabilities = 0; + private short _version = 0; + private short _rpcid = 0; + private int _maxToken = 0; + private string _name = null; + private string _comment = null; + + /* + * This is to support SSL under semi trusted environment. + * Note that it is only for SSL with no client cert + */ + internal SecurityPackageInfoClass(SafeHandle safeHandle, int index) + { + if (safeHandle.IsInvalid) + { + GlobalLog.Print("SecurityPackageInfoClass::.ctor() the pointer is invalid: " + (safeHandle.DangerousGetHandle()).ToString("x")); + return; + } + IntPtr unmanagedAddress = IntPtrHelper.Add(safeHandle.DangerousGetHandle(), SecurityPackageInfo.Size * index); + GlobalLog.Print("SecurityPackageInfoClass::.ctor() unmanagedPointer: " + ((long)unmanagedAddress).ToString("x")); + + _capabilities = Marshal.ReadInt32(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Capabilities")); + _version = Marshal.ReadInt16(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Version")); + _rpcid = Marshal.ReadInt16(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "RPCID")); + _maxToken = Marshal.ReadInt32(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "MaxToken")); + + IntPtr unmanagedString; + + unmanagedString = Marshal.ReadIntPtr(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Name")); + if (unmanagedString != IntPtr.Zero) + { + _name = Marshal.PtrToStringUni(unmanagedString); + GlobalLog.Print("Name: " + Name); + } + + unmanagedString = Marshal.ReadIntPtr(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Comment")); + if (unmanagedString != IntPtr.Zero) + { + _comment = Marshal.PtrToStringUni(unmanagedString); + GlobalLog.Print("Comment: " + _comment); + } + + GlobalLog.Print("SecurityPackageInfoClass::.ctor(): " + ToString()); + } + + internal int MaxToken + { + get { return _maxToken; } + } + + internal string Name + { + get { return _name; } + } + + public override string ToString() + { + return "Capabilities:" + String.Format(CultureInfo.InvariantCulture, "0x{0:x}", _capabilities) + + " Version:" + _version.ToString(NumberFormatInfo.InvariantInfo) + + " RPCID:" + _rpcid.ToString(NumberFormatInfo.InvariantInfo) + + " MaxToken:" + MaxToken.ToString(NumberFormatInfo.InvariantInfo) + + " Name:" + ((Name == null) ? "(null)" : Name) + + " Comment:" + ((_comment == null) ? "(null)" : _comment); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs new file mode 100644 index 0000000000..2430b73b8d --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + [StructLayout(LayoutKind.Sequential)] + internal class SslConnectionInfo + { + public readonly int Protocol; + public readonly int DataCipherAlg; + public readonly int DataKeySize; + public readonly int DataHashAlg; + public readonly int DataHashKeySize; + public readonly int KeyExchangeAlg; + public readonly int KeyExchKeySize; + + internal unsafe SslConnectionInfo(byte[] nativeBuffer) + { + fixed (void* voidPtr = nativeBuffer) + { + IntPtr unmanagedAddress = new IntPtr(voidPtr); + Protocol = Marshal.ReadInt32(unmanagedAddress); + DataCipherAlg = Marshal.ReadInt32(unmanagedAddress, 4); + DataKeySize = Marshal.ReadInt32(unmanagedAddress, 8); + DataHashAlg = Marshal.ReadInt32(unmanagedAddress, 12); + DataHashKeySize = Marshal.ReadInt32(unmanagedAddress, 16); + KeyExchangeAlg = Marshal.ReadInt32(unmanagedAddress, 20); + KeyExchKeySize = Marshal.ReadInt32(unmanagedAddress, 24); + } + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs new file mode 100644 index 0000000000..6be68aa96b --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Security.Windows +{ + [StructLayout(LayoutKind.Sequential)] + internal class StreamSizes + { + public int header; + public int trailer; + public int maximumMessage; + public int buffersCount; + public int blockSize; + + internal unsafe StreamSizes(byte[] memory) + { + fixed (void* voidPtr = memory) + { + IntPtr unmanagedAddress = new IntPtr(voidPtr); + try + { + header = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress)); + trailer = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 4)); + maximumMessage = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 8)); + buffersCount = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 12)); + blockSize = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 16)); + } + catch (OverflowException) + { + GlobalLog.Assert(false, "StreamSizes::.ctor", "Negative size."); + throw; + } + } + } + public static readonly int SizeOf = Marshal.SizeOf(typeof(StreamSizes)); + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs new file mode 100644 index 0000000000..3e8a40d344 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs @@ -0,0 +1,222 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Security; + +namespace Microsoft.AspNet.Security.Windows +{ + [System.Security.SuppressUnmanagedCodeSecurityAttribute] + internal static class UnsafeNclNativeMethods + { + private const string KERNEL32 = "kernel32.dll"; + private const string SECUR32 = "secur32.dll"; + private const string CRYPT32 = "crypt32.dll"; + + [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint GetCurrentThreadId(); + + [System.Security.SuppressUnmanagedCodeSecurityAttribute] + internal static class SafeNetHandles + { + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern int FreeContextBuffer( + [In] IntPtr contextBuffer); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern int FreeCredentialsHandle( + ref SSPIHandle handlePtr); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern int DeleteSecurityContext( + ref SSPIHandle handlePtr); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + internal static unsafe extern int AcceptSecurityContext( + ref SSPIHandle credentialHandle, + [In] void* inContextPtr, + [In] SecurityBufferDescriptor inputBuffer, + [In] ContextFlags inFlags, + [In] Endianness endianness, + ref SSPIHandle outContextPtr, + [In, Out] SecurityBufferDescriptor outputBuffer, + [In, Out] ref ContextFlags attributes, + out long timeStamp); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + internal static unsafe extern int QueryContextAttributesW( + ref SSPIHandle contextHandle, + [In] ContextAttribute attribute, + [In] void* buffer); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + internal static unsafe extern int SetContextAttributesW( + ref SSPIHandle contextHandle, + [In] ContextAttribute attribute, + [In] byte[] buffer, + [In] int bufferSize); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + internal static extern int EnumerateSecurityPackagesW( + [Out] out int pkgnum, + [Out] out SafeFreeContextBuffer handle); + + [DllImport(SECUR32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal static unsafe extern int AcquireCredentialsHandleW( + [In] string principal, + [In] string moduleName, + [In] int usage, + [In] void* logonID, + [In] ref AuthIdentity authdata, + [In] void* keyCallback, + [In] void* keyArgument, + ref SSPIHandle handlePtr, + [Out] out long timeStamp); + + [DllImport(SECUR32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal static unsafe extern int AcquireCredentialsHandleW( + [In] string principal, + [In] string moduleName, + [In] int usage, + [In] void* logonID, + [In] IntPtr zero, + [In] void* keyCallback, + [In] void* keyArgument, + ref SSPIHandle handlePtr, + [Out] out long timeStamp); + + // Win7+ + [DllImport(SECUR32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal static unsafe extern int AcquireCredentialsHandleW( + [In] string principal, + [In] string moduleName, + [In] int usage, + [In] void* logonID, + [In] SafeSspiAuthDataHandle authdata, + [In] void* keyCallback, + [In] void* keyArgument, + ref SSPIHandle handlePtr, + [Out] out long timeStamp); + + [DllImport(SECUR32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal static unsafe extern int AcquireCredentialsHandleW( + [In] string principal, + [In] string moduleName, + [In] int usage, + [In] void* logonID, + [In] ref SecureCredential authData, + [In] void* keyCallback, + [In] void* keyArgument, + ref SSPIHandle handlePtr, + [Out] out long timeStamp); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + internal static unsafe extern int InitializeSecurityContextW( + ref SSPIHandle credentialHandle, + [In] void* inContextPtr, + [In] byte* targetName, + [In] ContextFlags inFlags, + [In] int reservedI, + [In] Endianness endianness, + [In] SecurityBufferDescriptor inputBuffer, + [In] int reservedII, + ref SSPIHandle outContextPtr, + [In, Out] SecurityBufferDescriptor outputBuffer, + [In, Out] ref ContextFlags attributes, + out long timeStamp); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + internal static unsafe extern int CompleteAuthToken( + [In] void* inContextPtr, + [In, Out] SecurityBufferDescriptor inputBuffers); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + internal static extern int QuerySecurityContextToken(ref SSPIHandle phContext, [Out] out SafeCloseHandle handle); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern bool CloseHandle(IntPtr handle); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern IntPtr LocalFree(IntPtr handle); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); + + [DllImport(CRYPT32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern void CertFreeCertificateChain( + [In] IntPtr pChainContext); + + [DllImport(CRYPT32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern void CertFreeCertificateChainList( + [In] IntPtr ppChainContext); + + [DllImport(CRYPT32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern bool CertFreeCertificateContext( // Suppressing returned status check, it's always==TRUE, + [In] IntPtr certContext); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + internal static extern IntPtr GlobalFree(IntPtr handle); + } + + [System.Security.SuppressUnmanagedCodeSecurityAttribute] + internal static class NativeNTSSPI + { + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + internal static extern int EncryptMessage( + ref SSPIHandle contextHandle, + [In] uint qualityOfProtection, + [In, Out] SecurityBufferDescriptor inputOutput, + [In] uint sequenceNumber); + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + internal static unsafe extern int DecryptMessage( + [In] ref SSPIHandle contextHandle, + [In, Out] SecurityBufferDescriptor inputOutput, + [In] uint sequenceNumber, + uint* qualityOfProtection); + } // class UnsafeNclNativeMethods.NativeNTSSPI + + [SuppressUnmanagedCodeSecurityAttribute] + internal static class SspiHelper + { + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + internal static unsafe extern SecurityStatus SspiFreeAuthIdentity( + [In] IntPtr authData); + + [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage", Justification = "Implementation requires unmanaged code usage")] + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)] + internal static unsafe extern SecurityStatus SspiEncodeStringsAsAuthIdentity( + [In] string userName, + [In] string domainName, + [In] string password, + [Out] out SafeSspiAuthDataHandle authData); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs b/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs new file mode 100644 index 0000000000..ab7367c456 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs @@ -0,0 +1,70 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Security.Windows +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Globalization; + using System.Runtime.InteropServices; + + internal class NegotiationInfoClass + { + internal const string NTLM = "NTLM"; + internal const string Kerberos = "Kerberos"; + internal const string WDigest = "WDigest"; + internal const string Digest = "Digest"; + internal const string Negotiate = "Negotiate"; + internal string AuthenticationPackage; + + internal NegotiationInfoClass(SafeHandle safeHandle, int negotiationState) + { + if (safeHandle.IsInvalid) + { + GlobalLog.Print("NegotiationInfoClass::.ctor() the handle is invalid:" + (safeHandle.DangerousGetHandle()).ToString("x")); + return; + } + IntPtr packageInfo = safeHandle.DangerousGetHandle(); + GlobalLog.Print("NegotiationInfoClass::.ctor() packageInfo:" + packageInfo.ToString("x8") + " negotiationState:" + negotiationState.ToString("x8")); + + const int SECPKG_NEGOTIATION_COMPLETE = 0; + const int SECPKG_NEGOTIATION_OPTIMISTIC = 1; + // const int SECPKG_NEGOTIATION_IN_PROGRESS = 2; + // const int SECPKG_NEGOTIATION_DIRECT = 3; + // const int SECPKG_NEGOTIATION_TRY_MULTICRED = 4; + + if (negotiationState == SECPKG_NEGOTIATION_COMPLETE || negotiationState == SECPKG_NEGOTIATION_OPTIMISTIC) + { + IntPtr unmanagedString = Marshal.ReadIntPtr(packageInfo, SecurityPackageInfo.NameOffest); + string name = null; + if (unmanagedString != IntPtr.Zero) + { + name = Marshal.PtrToStringUni(unmanagedString); + } + GlobalLog.Print("NegotiationInfoClass::.ctor() packageInfo:" + packageInfo.ToString("x8") + " negotiationState:" + negotiationState.ToString("x8") + " name:" + ValidationHelper.ToString(name)); + + // an optimization for future string comparisons + if (string.Compare(name, Kerberos, StringComparison.OrdinalIgnoreCase) == 0) + { + AuthenticationPackage = Kerberos; + } + else if (string.Compare(name, NTLM, StringComparison.OrdinalIgnoreCase) == 0) + { + AuthenticationPackage = NTLM; + } + else if (string.Compare(name, WDigest, StringComparison.OrdinalIgnoreCase) == 0) + { + AuthenticationPackage = WDigest; + } + else + { + AuthenticationPackage = name; + } + } + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs b/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs new file mode 100644 index 0000000000..37a2caa049 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs @@ -0,0 +1,109 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class PrefixCollection : ICollection + { + private WindowsAuthMiddleware _winAuth; + + internal PrefixCollection(WindowsAuthMiddleware winAuth) + { + _winAuth = winAuth; + } + + public int Count + { + get + { + return _winAuth._uriPrefixes.Count; + } + } + + public bool IsSynchronized + { + get + { + return false; + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public void CopyTo(Array array, int offset) + { + if (Count > array.Length) + { + throw new ArgumentOutOfRangeException("array", SR.GetString(SR.net_array_too_small)); + } + if (offset + Count > array.Length) + { + throw new ArgumentOutOfRangeException("offset"); + } + int index = 0; + foreach (string uriPrefix in _winAuth._uriPrefixes.Keys) + { + array.SetValue(uriPrefix, offset + index++); + } + } + + public void CopyTo(string[] array, int offset) + { + if (Count > array.Length) + { + throw new ArgumentOutOfRangeException("array", SR.GetString(SR.net_array_too_small)); + } + if (offset + Count > array.Length) + { + throw new ArgumentOutOfRangeException("offset"); + } + int index = 0; + foreach (string uriPrefix in _winAuth._uriPrefixes.Keys) + { + array[offset + index++] = uriPrefix; + } + } + + public void Add(string uriPrefix) + { + _winAuth.AddPrefix(uriPrefix); + } + + public bool Contains(string uriPrefix) + { + return _winAuth._uriPrefixes.Contains(uriPrefix); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return new PrefixEnumerator(_winAuth._uriPrefixes.Keys.GetEnumerator()); + } + + public bool Remove(string uriPrefix) + { + return _winAuth.RemovePrefix(uriPrefix); + } + + public void Clear() + { + _winAuth.RemoveAll(true); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs b/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs new file mode 100644 index 0000000000..40de3afd6d --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System.Collections; +using System.Collections.Generic; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class PrefixEnumerator : IEnumerator + { + private IEnumerator enumerator; + + internal PrefixEnumerator(IEnumerator enumerator) + { + this.enumerator = enumerator; + } + + public string Current + { + get + { + return (string)enumerator.Current; + } + } + + object System.Collections.IEnumerator.Current + { + get + { + return enumerator.Current; + } + } + + public bool MoveNext() + { + return enumerator.MoveNext(); + } + + public void Dispose() + { + } + + void System.Collections.IEnumerator.Reset() + { + enumerator.Reset(); + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Security.Windows/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..501727a48a --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Properties/AssemblyInfo.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.AspNet.Security.Windows")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.AspNet.Security.Windows")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1f471909-581f-4060-a147-430891e9c3c1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("0.5")] +[assembly: AssemblyVersion("0.5")] +[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs b/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs new file mode 100644 index 0000000000..7d2d33ff00 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs @@ -0,0 +1,368 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Net; +using System.Security.Authentication.ExtendedProtection; + +namespace Microsoft.AspNet.Security.Windows +{ + internal class ServiceNameStore + { + private List serviceNames; + private ServiceNameCollection serviceNameCollection; + + public ServiceNameStore() + { + serviceNames = new List(); + serviceNameCollection = null; // set only when needed (due to expensive item-by-item copy) + } + + public ServiceNameCollection ServiceNames + { + get + { + if (serviceNameCollection == null) + { + serviceNameCollection = new ServiceNameCollection(serviceNames); + } + return serviceNameCollection; + } + } + + private bool AddSingleServiceName(string spn) + { + spn = NormalizeServiceName(spn); + if (Contains(spn)) + { + return false; + } + else + { + serviceNames.Add(spn); + return true; + } + } + + public bool Add(string uriPrefix) + { + Debug.Assert(!String.IsNullOrEmpty(uriPrefix)); + + string[] newServiceNames = BuildServiceNames(uriPrefix); + + bool addedAny = false; + foreach (string spn in newServiceNames) + { + if (AddSingleServiceName(spn)) + { + addedAny = true; + + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, "ServiceNameStore#" + + ValidationHelper.HashString(this) + "::Add() " + + SR.GetString(SR.net_log_listener_spn_add, spn, uriPrefix)); + } + } + } + + if (addedAny) + { + serviceNameCollection = null; + } + else if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, "ServiceNameStore#" + + ValidationHelper.HashString(this) + "::Add() " + + SR.GetString(SR.net_log_listener_spn_not_add, uriPrefix)); + } + + return addedAny; + } + + public bool Remove(string uriPrefix) + { + Debug.Assert(!String.IsNullOrEmpty(uriPrefix)); + + string newServiceName = BuildSimpleServiceName(uriPrefix); + newServiceName = NormalizeServiceName(newServiceName); + bool needToRemove = Contains(newServiceName); + + if (needToRemove) + { + serviceNames.Remove(newServiceName); + serviceNameCollection = null; // invalidate (readonly) ServiceNameCollection + } + + if (Logging.On) + { + if (needToRemove) + { + Logging.PrintInfo(Logging.HttpListener, "ServiceNameStore#" + + ValidationHelper.HashString(this) + "::Remove() " + + SR.GetString(SR.net_log_listener_spn_remove, newServiceName, uriPrefix)); + } + else + { + Logging.PrintInfo(Logging.HttpListener, "ServiceNameStore#" + + ValidationHelper.HashString(this) + "::Remove() " + + SR.GetString(SR.net_log_listener_spn_not_remove, uriPrefix)); + } + } + + return needToRemove; + } + + // Assumes already normalized + private bool Contains(string newServiceName) + { + if (newServiceName == null) + { + return false; + } + + return Contains(newServiceName, serviceNames); + } + + // Assumes searchServiceName and serviceNames have already been normalized + internal static bool Contains(string searchServiceName, ICollection serviceNames) + { + Debug.Assert(serviceNames != null); + Debug.Assert(!String.IsNullOrEmpty(searchServiceName)); + + foreach (string serviceName in serviceNames) + { + if (Match(serviceName, searchServiceName)) + { + return true; + } + } + + return false; + } + + // Assumes already normalized + internal static bool Match(string serviceName1, string serviceName2) + { + return (String.Compare(serviceName1, serviceName2, StringComparison.OrdinalIgnoreCase) == 0); + } + + public void Clear() + { + serviceNames.Clear(); + serviceNameCollection = null; // invalidate (readonly) ServiceNameCollection + } + + private string ExtractHostname(string uriPrefix, bool allowInvalidUriStrings) + { + if (Uri.IsWellFormedUriString(uriPrefix, UriKind.Absolute)) + { + Uri hostUri = new Uri(uriPrefix); + return hostUri.Host; + } + else if (allowInvalidUriStrings) + { + int i = uriPrefix.IndexOf("://") + 3; + int j = i; + + bool inSquareBrackets = false; + while (j < uriPrefix.Length && uriPrefix[j] != '/' && (uriPrefix[j] != ':' || inSquareBrackets)) + { + if (uriPrefix[j] == '[') + { + if (inSquareBrackets) + { + j = i; + break; + } + inSquareBrackets = true; + } + if (inSquareBrackets && uriPrefix[j] == ']') + { + inSquareBrackets = false; + } + j++; + } + + return uriPrefix.Substring(i, j - i); + } + + return null; + } + + public string BuildSimpleServiceName(string uriPrefix) + { + string hostname = ExtractHostname(uriPrefix, false); + + if (hostname != null) + { + return "HTTP/" + hostname; + } + else + { + return null; + } + } + + public string[] BuildServiceNames(string uriPrefix) + { + string hostname = ExtractHostname(uriPrefix, true); + + IPAddress ipAddress = null; + if (String.Compare(hostname, "*", StringComparison.InvariantCultureIgnoreCase) == 0 || + String.Compare(hostname, "+", StringComparison.InvariantCultureIgnoreCase) == 0 || + IPAddress.TryParse(hostname, out ipAddress)) + { + // for a wildcard, register the machine name. If the caller doesn't have DNS permission + // or the query fails for some reason, don't add an SPN. + try + { + string machineName = Dns.GetHostEntry(String.Empty).HostName; + return new string[] { "HTTP/" + machineName }; + } + catch (System.Net.Sockets.SocketException) + { + return new string[0]; + } + catch (System.Security.SecurityException) + { + return new string[0]; + } + } + else if (!hostname.Contains(".")) + { + // for a dotless name, try to resolve the FQDN. If the caller doesn't have DNS permission + // or the query fails for some reason, add only the dotless name. + try + { + string fqdn = Dns.GetHostEntry(hostname).HostName; + return new string[] { "HTTP/" + hostname, "HTTP/" + fqdn }; + } + catch (System.Net.Sockets.SocketException) + { + return new string[] { "HTTP/" + hostname }; + } + catch (System.Security.SecurityException) + { + return new string[] { "HTTP/" + hostname }; + } + } + else + { + return new string[] { "HTTP/" + hostname }; + } + } + + // Normalizes any punycode to unicode in an Service Name (SPN) host. + // If the algorithm fails at any point then the original input is returned. + // ServiceName is in one of the following forms: + // prefix/host + // prefix/host:port + // prefix/host/DistinguishedName + // prefix/host:port/DistinguishedName + internal static string NormalizeServiceName(string inputServiceName) + { + if (string.IsNullOrWhiteSpace(inputServiceName)) + { + return inputServiceName; + } + + // Separate out the prefix + int shashIndex = inputServiceName.IndexOf('/'); + if (shashIndex < 0) + { + return inputServiceName; + } + string prefix = inputServiceName.Substring(0, shashIndex + 1); // Includes slash + string hostPortAndDistinguisher = inputServiceName.Substring(shashIndex + 1); // Excludes slash + + if (string.IsNullOrWhiteSpace(hostPortAndDistinguisher)) + { + return inputServiceName; + } + + string host = hostPortAndDistinguisher; + string port = string.Empty; + string distinguisher = string.Empty; + + // Check for the absence of a port or distinguisher. + UriHostNameType hostType = Uri.CheckHostName(hostPortAndDistinguisher); + if (hostType == UriHostNameType.Unknown) + { + string hostAndPort = hostPortAndDistinguisher; + + // Check for distinguisher + int nextSlashIndex = hostPortAndDistinguisher.IndexOf('/'); + if (nextSlashIndex >= 0) + { + // host:port/distinguisher or host/distinguisher + hostAndPort = hostPortAndDistinguisher.Substring(0, nextSlashIndex); // Excludes Slash + distinguisher = hostPortAndDistinguisher.Substring(nextSlashIndex); // Includes Slash + host = hostAndPort; // We don't know if there is a port yet. + + // No need to validate the distinguisher + } + + // Check for port + int colonIndex = hostAndPort.LastIndexOf(':'); // Allow IPv6 addresses + if (colonIndex >= 0) + { + // host:port + host = hostAndPort.Substring(0, colonIndex); // Excludes colon + port = hostAndPort.Substring(colonIndex + 1); // Excludes colon + + // Loosely validate the port just to make sure it was a port and not something else + UInt16 portValue; + if (!UInt16.TryParse(port, NumberStyles.Integer, CultureInfo.InvariantCulture, out portValue)) + { + return inputServiceName; + } + + // Re-include the colon for the final output. Do not change the port format. + port = hostAndPort.Substring(colonIndex); + } + + hostType = Uri.CheckHostName(host); // Revaidate the host + } + + if (hostType != UriHostNameType.Dns) + { + // UriHostNameType.IPv4, UriHostNameType.IPv6: Do not normalize IPv4/6 hosts. + // UriHostNameType.Basic: This is never returned by CheckHostName today + // UriHostNameType.Unknown: Nothing recognizable to normalize + // default Some new UriHostNameType? + return inputServiceName; + } + + // Now we have a valid DNS host, normalize it. + + Uri constructedUri; + // This shouldn't fail, but we need to avoid any unexpected exceptions on this code path. + if (!Uri.TryCreate(Uri.UriSchemeHttp + Uri.SchemeDelimiter + host, UriKind.Absolute, out constructedUri)) + { + return inputServiceName; + } + + string normalizedHost = constructedUri.GetComponents( + UriComponents.NormalizedHost, UriFormat.SafeUnescaped); + + string normalizedServiceName = string.Format(CultureInfo.InvariantCulture, + "{0}{1}{2}{3}", prefix, normalizedHost, port, distinguisher); + + // Don't return the new one unless we absolutely have to. It may have only changed casing. + if (String.Compare(inputServiceName, normalizedServiceName, StringComparison.OrdinalIgnoreCase) == 0) + { + return inputServiceName; + } + + return normalizedServiceName; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs b/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs new file mode 100644 index 0000000000..85f696728f --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs @@ -0,0 +1,1281 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Net; +using System.Security.Authentication.ExtendedProtection; +using System.Security.Permissions; +using System.Security.Principal; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Security.Windows +{ + using AppFunc = Func, Task>; + + /// + /// A middleware that performs Windows Authentication of the specified types. + /// + public sealed class WindowsAuthMiddleware + { + private Func, AuthTypes> _authenticationDelegate; + private AuthTypes _authenticationScheme = AuthTypes.Negotiate | AuthTypes.Ntlm | AuthTypes.Digest; + private string _realm; + private PrefixCollection _prefixes; + private bool _unsafeConnectionNtlmAuthentication; + private Func, ExtendedProtectionPolicy> _extendedProtectionSelectorDelegate; + private ExtendedProtectionPolicy _extendedProtectionPolicy; + private ServiceNameStore _defaultServiceNames; + + private Hashtable _disconnectResults; // ulong -> DisconnectAsyncResult + private object _internalLock; + + internal Hashtable _uriPrefixes; + private DigestCache _digestCache; + + private AppFunc _nextApp; + + // TODO: Support proxy auth + // private bool _doProxyAuth; + + /// + /// + /// + /// + public WindowsAuthMiddleware(AppFunc nextApp) + { + if (Logging.On) + { + Logging.Enter(Logging.HttpListener, this, "WindowsAuth", string.Empty); + } + + _internalLock = new object(); + _defaultServiceNames = new ServiceNameStore(); + + // default: no CBT checks on any platform (appcompat reasons); applies also to PolicyEnforcement + // config element + _extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never); + _uriPrefixes = new Hashtable(); + _digestCache = new DigestCache(); + + _nextApp = nextApp; + + if (Logging.On) + { + Logging.Exit(Logging.HttpListener, this, "WindowsAuth", string.Empty); + } + } + + /// + /// Dynamically select the type of authentication to apply per request. + /// + public Func, AuthTypes> AuthenticationSchemeSelectorDelegate + { + get + { + return _authenticationDelegate; + } + set + { + _authenticationDelegate = value; + } + } + + /// + /// Dynamically select the type of extended protection to apply per request. + /// + public Func, ExtendedProtectionPolicy> ExtendedProtectionSelectorDelegate + { + get + { + return _extendedProtectionSelectorDelegate; + } + set + { + if (value == null) + { + throw new ArgumentNullException(); + } + + if (!ExtendedProtectionPolicy.OSSupportsExtendedProtection) + { + throw new PlatformNotSupportedException(SR.GetString(SR.security_ExtendedProtection_NoOSSupport)); + } + + _extendedProtectionSelectorDelegate = value; + } + } + + /// + /// Specifies which types of Windows authentication are enabled. + /// + public AuthTypes AuthenticationSchemes + { + get + { + return _authenticationScheme; + } + set + { + _authenticationScheme = value; + } + } + + /// + /// Configures extended protection. + /// + public ExtendedProtectionPolicy ExtendedProtectionPolicy + { + get + { + return _extendedProtectionPolicy; + } + set + { + if (value == null) + { + throw new ArgumentNullException("value"); + } + if (!ExtendedProtectionPolicy.OSSupportsExtendedProtection && value.PolicyEnforcement == PolicyEnforcement.Always) + { + throw new PlatformNotSupportedException(SR.GetString(SR.security_ExtendedProtection_NoOSSupport)); + } + if (value.CustomChannelBinding != null) + { + throw new ArgumentException(SR.GetString(SR.net_listener_cannot_set_custom_cbt), "CustomChannelBinding"); + } + + _extendedProtectionPolicy = value; + } + } + + /// + /// Configures the service names for extended protection. + /// + public ServiceNameCollection DefaultServiceNames + { + get + { + return _defaultServiceNames.ServiceNames; + } + } + + /// + /// The Realm for use in digest authentication. + /// + public string Realm + { + get + { + return _realm; + } + set + { + _realm = value; + } + } + + /// + /// Enables authenticated connection sharing with NTLM. + /// + public bool UnsafeConnectionNtlmAuthentication + { + get + { + return _unsafeConnectionNtlmAuthentication; + } + + set + { + if (_unsafeConnectionNtlmAuthentication == value) + { + return; + } + lock (DisconnectResults.SyncRoot) + { + if (_unsafeConnectionNtlmAuthentication == value) + { + return; + } + _unsafeConnectionNtlmAuthentication = value; + if (!value) + { + foreach (DisconnectAsyncResult result in DisconnectResults.Values) + { + result.AuthenticatedUser = null; + } + } + } + } + } + + internal Hashtable DisconnectResults + { + get + { + if (_disconnectResults == null) + { + Interlocked.CompareExchange(ref _disconnectResults, Hashtable.Synchronized(new Hashtable()), null); + } + return _disconnectResults; + } + } + + internal unsafe void AddPrefix(string uriPrefix) + { + if (Logging.On) + { + Logging.Enter(Logging.HttpListener, this, "AddPrefix", "uriPrefix:" + uriPrefix); + } + string registeredPrefix = null; + try + { + if (uriPrefix == null) + { + throw new ArgumentNullException("uriPrefix"); + } + (new WebPermission(NetworkAccess.Accept, uriPrefix)).Demand(); + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::AddPrefix() uriPrefix:" + uriPrefix); + int i; + if (string.Compare(uriPrefix, 0, "http://", 0, 7, StringComparison.OrdinalIgnoreCase) == 0) + { + i = 7; + } + else if (string.Compare(uriPrefix, 0, "https://", 0, 8, StringComparison.OrdinalIgnoreCase) == 0) + { + i = 8; + } + else + { + throw new ArgumentException(SR.GetString(SR.net_listener_scheme), "uriPrefix"); + } + bool inSquareBrakets = false; + int j = i; + while (j < uriPrefix.Length && uriPrefix[j] != '/' && (uriPrefix[j] != ':' || inSquareBrakets)) + { + if (uriPrefix[j] == '[') + { + if (inSquareBrakets) + { + j = i; + break; + } + inSquareBrakets = true; + } + if (inSquareBrakets && uriPrefix[j] == ']') + { + inSquareBrakets = false; + } + j++; + } + if (i == j) + { + throw new ArgumentException(SR.GetString(SR.net_listener_host), "uriPrefix"); + } + if (uriPrefix[uriPrefix.Length - 1] != '/') + { + throw new ArgumentException(SR.GetString(SR.net_listener_slash), "uriPrefix"); + } + registeredPrefix = uriPrefix[j] == ':' ? String.Copy(uriPrefix) : uriPrefix.Substring(0, j) + (i == 7 ? ":80" : ":443") + uriPrefix.Substring(j); + fixed (char* pChar = registeredPrefix) + { + i = 0; + while (pChar[i] != ':') + { + pChar[i] = (char)CaseInsensitiveAscii.AsciiToLower[(byte)pChar[i]]; + i++; + } + } + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::AddPrefix() mapped uriPrefix:" + uriPrefix + " to registeredPrefix:" + registeredPrefix); + + _uriPrefixes[uriPrefix] = registeredPrefix; + _defaultServiceNames.Add(uriPrefix); + } + catch (Exception exception) + { + if (Logging.On) + { + Logging.Exception(Logging.HttpListener, this, "AddPrefix", exception); + } + throw; + } + finally + { + if (Logging.On) + { + Logging.Exit(Logging.HttpListener, this, "AddPrefix", "prefix:" + registeredPrefix); + } + } + } + + internal PrefixCollection Prefixes + { + get + { + if (Logging.On) + { + Logging.Enter(Logging.HttpListener, this, "Prefixes_get", string.Empty); + } + if (_prefixes == null) + { + _prefixes = new PrefixCollection(this); + } + return _prefixes; + } + } + + internal bool RemovePrefix(string uriPrefix) + { + if (Logging.On) + { + Logging.Enter(Logging.HttpListener, this, "RemovePrefix", "uriPrefix:" + uriPrefix); + } + try + { + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::RemovePrefix() uriPrefix:" + uriPrefix); + if (uriPrefix == null) + { + throw new ArgumentNullException("uriPrefix"); + } + + if (!_uriPrefixes.Contains(uriPrefix)) + { + return false; + } + + _uriPrefixes.Remove(uriPrefix); + _defaultServiceNames.Remove(uriPrefix); + } + catch (Exception exception) + { + if (Logging.On) + { + Logging.Exception(Logging.HttpListener, this, "RemovePrefix", exception); + } + throw; + } + finally + { + if (Logging.On) + { + Logging.Exit(Logging.HttpListener, this, "RemovePrefix", "uriPrefix:" + uriPrefix); + } + } + return true; + } + + internal void RemoveAll(bool clear) + { + if (Logging.On) + { + Logging.Enter(Logging.HttpListener, this, "RemoveAll", string.Empty); + } + try + { + // go through the uri list and unregister for each one of them + if (_uriPrefixes.Count > 0) + { + if (clear) + { + _uriPrefixes.Clear(); + _defaultServiceNames.Clear(); + } + } + } + finally + { + if (Logging.On) + { + Logging.Exit(Logging.HttpListener, this, "RemoveAll", string.Empty); + } + } + } + + // old API, now private, and helper methods + private void Dispose(bool disposing) + { + GlobalLog.Assert(disposing, "Dispose(bool) does nothing if called from the finalizer."); + + if (!disposing) + { + return; + } + + try + { + _digestCache.Dispose(); + } + finally + { + if (Logging.On) + { + Logging.Exit(Logging.HttpListener, this, "Dispose", string.Empty); + } + } + } + + /// + /// + /// + /// + /// + public Task Invoke(IDictionary env) + { + // Process the auth header, if any + if (!TryHandleAuthentication(env)) + { + // If failed and a 400/401/500 was sent. + return Task.FromResult(null); + } + + // If passing through, register for OnSendingHeaders. Add an auth header challenge on 401. + var registerOnSendingHeaders = env.Get, object>>(Constants.ServerOnSendingHeadersKey); + if (registerOnSendingHeaders == null) + { + // This module requires OnSendingHeaders support. + throw new PlatformNotSupportedException(); + } + registerOnSendingHeaders(Set401Challenges, env); + + // Invoke the next item in the app chain + return _nextApp(env); + } + + // Returns true if auth completed successfully (or anonymous), false if there was an auth header + // but processing it failed. + private bool TryHandleAuthentication(IDictionary env) + { + DisconnectAsyncResult disconnectResult; + object connectionId = env.Get(Constants.ServerConnectionIdKey, -1); + string authorizationHeader = null; + if (!TryGetIncomingAuthHeader(env, out authorizationHeader)) + { + if (UnsafeConnectionNtlmAuthentication) + { + disconnectResult = (DisconnectAsyncResult)DisconnectResults[connectionId]; + if (disconnectResult != null) + { + WindowsPrincipal principal = disconnectResult.AuthenticatedUser; + if (principal != null) + { + // This connection has already been authenticated; + SetIdentity(env, principal, null); + } + } + } + + return true; // Anonymous or UnsafeConnectionNtlmAuthentication + } + + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() authorizationHeader:" + ValidationHelper.ToString(authorizationHeader)); + + if (UnsafeConnectionNtlmAuthentication) + { + disconnectResult = (DisconnectAsyncResult)DisconnectResults[connectionId]; + // They sent an authorization header - destroy their previous credentials. + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() clearing principal cache"); + if (disconnectResult != null) + { + disconnectResult.AuthenticatedUser = null; + } + } + + try + { + AuthTypes headerScheme; + string inBlob; + if (!TryGetRecognizedAuthScheme(authorizationHeader, out headerScheme, out inBlob)) + { + return true; // Anonymous / pass through + } + Contract.Assert(headerScheme != AuthTypes.None); + Contract.Assert(inBlob != null); + + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() Performing Authentication headerScheme:" + ValidationHelper.ToString(headerScheme)); + switch (headerScheme) + { + case AuthTypes.Digest: + return TryAuthenticateWithDigest(env, inBlob); + + case AuthTypes.Negotiate: + case AuthTypes.Ntlm: + string package = headerScheme == AuthTypes.Ntlm ? NegotiationInfoClass.NTLM : NegotiationInfoClass.Negotiate; + return TryAuthenticateWithNegotiate(env, package, inBlob); + + default: + throw new NotImplementedException(headerScheme.ToString()); + } + } + catch (Exception) + { + SendError(env, HttpStatusCode.InternalServerError, null); + return false; + } + } + + // TODO: Support proxy auth + private bool TryGetIncomingAuthHeader(IDictionary env, out string authorizationHeader) + { + IDictionary headers = env.Get>(Constants.RequestHeadersKey); + authorizationHeader = headers.Get("Authorization"); + return !string.IsNullOrWhiteSpace(authorizationHeader); + } + + private bool TryGetRecognizedAuthScheme(string authorizationHeader, out AuthTypes headerScheme, out string inBlob) + { + headerScheme = AuthTypes.None; + + int index; + // Find the end of the scheme name. Trust that HTTP.SYS parsed out just our header ok. + for (index = 0; index < authorizationHeader.Length; index++) + { + if (authorizationHeader[index] == ' ' || authorizationHeader[index] == '\t' || + authorizationHeader[index] == '\r' || authorizationHeader[index] == '\n') + { + break; + } + } + + // Currently only allow one Authorization scheme/header per request. + if (index < authorizationHeader.Length) + { + if ((AuthenticationSchemes & AuthTypes.Negotiate) != AuthTypes.None && + string.Compare(authorizationHeader, 0, NegotiationInfoClass.Negotiate, 0, index, StringComparison.OrdinalIgnoreCase) == 0) + { + headerScheme = AuthTypes.Negotiate; + } + else if ((AuthenticationSchemes & AuthTypes.Ntlm) != AuthTypes.None && + string.Compare(authorizationHeader, 0, NegotiationInfoClass.NTLM, 0, index, StringComparison.OrdinalIgnoreCase) == 0) + { + headerScheme = AuthTypes.Ntlm; + } + else if ((AuthenticationSchemes & AuthTypes.Digest) != AuthTypes.None && + string.Compare(authorizationHeader, 0, NegotiationInfoClass.Digest, 0, index, StringComparison.OrdinalIgnoreCase) == 0) + { + headerScheme = AuthTypes.Digest; + } + } + + // Find the beginning of the blob. Trust that HTTP.SYS parsed out just our header ok. + for (index++; index < authorizationHeader.Length; index++) + { + if (authorizationHeader[index] != ' ' && authorizationHeader[index] != '\t' && + authorizationHeader[index] != '\r' && authorizationHeader[index] != '\n') + { + break; + } + } + inBlob = index < authorizationHeader.Length ? authorizationHeader.Substring(index) : string.Empty; + + return headerScheme != AuthTypes.None; + } + + // Returns true if successfully authenticated via Digest. Returns false if a 401 was sent. + private bool TryAuthenticateWithDigest(IDictionary env, string inBlob) + { + NTAuthentication context = null; + IPrincipal principal = null; + SecurityStatus statusCodeNew; + ChannelBinding binding; + string outBlob; + HttpStatusCode httpError = HttpStatusCode.OK; + string verb = env.Get(Constants.RequestMethodKey); + bool isSecureConnection = IsSecureConnection(env); + // GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() package:WDigest headerScheme:" + headerScheme); + + // WDigest had some weird behavior. This is what I have discovered: + // Local accounts don't work, only domain accounts. The domain (i.e. REDMOND) is implied. Not sure how it is chosen. + // If the domain is specified and the credentials are correct, it works. If they're not (domain, username or password): + // AcceptSecurityContext (GetOutgoingDigestBlob) returns success but with a bogus 4k challenge, and + // QuerySecurityContextToken (GetContextToken) fails with NoImpersonation. + // If the domain isn't specified, AcceptSecurityContext returns NoAuthenticatingAuthority for a bad username, + // and LogonDenied for a bad password. + + // Also interesting is that WDigest requires us to keep a reference to the previous context, but fails if we + // actually pass it in! (It't ok to pass it in for the first request, but not if nc > 1.) For Whidbey, + // we create a new context and associate it with the connection, just like NTLM, but instead of using it for + // the next request on the connection, we always create a new context and swap the old one out. As long + // as we keep the old one around until after we authenticate with the new one, it works. For this reason, + // we also keep these contexts around past the lifetime of the connection, so that KeepAlive=false works. + binding = GetChannelBinding(env, isSecureConnection, ExtendedProtectionPolicy); + + context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null, + GetContextFlags(ExtendedProtectionPolicy, isSecureConnection), binding); + + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() verb:" + verb + " context.IsValidContext:" + context.IsValidContext.ToString()); + + outBlob = context.GetOutgoingDigestBlob(inBlob, verb, null, Realm, false, false, out statusCodeNew); + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew + " outBlob:[" + outBlob + "]"); + + // WDigest bug: sometimes when AcceptSecurityContext returns success, it provides a bogus, empty 4k buffer. + // Ignore it. (Should find out what's going on here from WDigest people.) + if (statusCodeNew == SecurityStatus.OK) + { + outBlob = null; + } + + IList challenges = null; + if (outBlob != null) + { + string challenge = NegotiationInfoClass.Digest + " " + outBlob; + AddChallenge(ref challenges, challenge); + } + + if (context.IsValidContext) + { + SafeCloseHandle userContext = null; + try + { + if (!CheckSpn(context, isSecureConnection, ExtendedProtectionPolicy)) + { + httpError = HttpStatusCode.Unauthorized; + } + else + { + SetServiceName(env, context.ClientSpecifiedSpn); + + userContext = context.GetContextToken(out statusCodeNew); + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() returned:" + statusCodeNew.ToString()); + if (statusCodeNew != SecurityStatus.OK) + { + httpError = HttpStatusFromSecurityStatus(statusCodeNew); + } + else if (userContext == null) + { + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() error: GetContextToken() returned:null statusCodeNew:" + statusCodeNew.ToString()); + httpError = HttpStatusCode.Unauthorized; + } + else + { + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8")); + principal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), "Digest"/*DigestClient.AuthType*/, WindowsAccountType.Normal, true)); + SetIdentity(env, principal, null); + _digestCache.SaveDigestContext(context); + } + } + } + finally + { + if (userContext != null) + { + userContext.Dispose(); + } + } + } + else + { + httpError = HttpStatusFromSecurityStatus(statusCodeNew); + } + + if (httpError != HttpStatusCode.OK) + { + SendError(env, httpError, challenges); + return false; + } + return true; + } + + // Negotiate or NTLM + private bool TryAuthenticateWithNegotiate(IDictionary env, string package, string inBlob) + { + object connectionId = env.Get(Constants.ServerConnectionIdKey, null); + if (connectionId == null) + { + // We need a connection ID from the server to correctly track in-progress auth. + throw new PlatformNotSupportedException(); + } + + NTAuthentication oldContext = null, context; + DisconnectAsyncResult disconnectResult = (DisconnectAsyncResult)DisconnectResults[connectionId]; + if (disconnectResult != null) + { + oldContext = disconnectResult.Session; + } + ChannelBinding binding; + bool isSecureConnection = IsSecureConnection(env); + byte[] bytes = null; + HttpStatusCode httpError = HttpStatusCode.OK; + bool error = false; + string outBlob = null; + + if (oldContext != null && oldContext.Package == package) + { + context = oldContext; + } + else + { + binding = GetChannelBinding(env, isSecureConnection, ExtendedProtectionPolicy); + + context = new NTAuthentication(true, package, null, + GetContextFlags(ExtendedProtectionPolicy, isSecureConnection), binding); + + // Clean up old context + if (oldContext != null) + { + oldContext.CloseContext(); + } + } + + try + { + bytes = Convert.FromBase64String(inBlob); + } + catch (FormatException) + { + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() FromBase64String threw a FormatException."); + httpError = HttpStatusCode.BadRequest; + error = true; + } + + byte[] decodedOutgoingBlob = null; + SecurityStatus statusCodeNew; + if (!error) + { + decodedOutgoingBlob = context.GetOutgoingBlob(bytes, false, out statusCodeNew); + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew); + error = !context.IsValidContext; + if (error) + { + // Bug #474228: SSPI Workaround + // If a client sends up a blob on the initial request, Negotiate returns SEC_E_INVALID_HANDLE + // when it should return SEC_E_INVALID_TOKEN. + if (statusCodeNew == SecurityStatus.InvalidHandle && oldContext == null && bytes != null && bytes.Length > 0) + { + statusCodeNew = SecurityStatus.InvalidToken; + } + + httpError = HttpStatusFromSecurityStatus(statusCodeNew); + } + } + + if (decodedOutgoingBlob != null) + { + outBlob = Convert.ToBase64String(decodedOutgoingBlob); + } + + if (!error) + { + if (context.IsCompleted) + { + SafeCloseHandle userContext = null; + try + { + if (!CheckSpn(context, isSecureConnection, ExtendedProtectionPolicy)) + { + httpError = HttpStatusCode.Unauthorized; + } + else + { + SetServiceName(env, context.ClientSpecifiedSpn); + + userContext = context.GetContextToken(out statusCodeNew); + if (statusCodeNew != SecurityStatus.OK) + { + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() failed with statusCodeNew:" + statusCodeNew.ToString()); + httpError = HttpStatusFromSecurityStatus(statusCodeNew); + } + else + { + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8")); + WindowsPrincipal windowsPrincipal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), context.ProtocolName, WindowsAccountType.Normal, true)); + SetIdentity(env, windowsPrincipal, outBlob); + + // if appropriate, cache this credential on this connection + if (UnsafeConnectionNtlmAuthentication + && context.ProtocolName.Equals(NegotiationInfoClass.NTLM, StringComparison.OrdinalIgnoreCase)) + { + // We may need to call WaitForDisconnect. + if (disconnectResult == null) + { + RegisterForDisconnectNotification(env, out disconnectResult); + } + + if (disconnectResult != null) + { + lock (DisconnectResults.SyncRoot) + { + if (UnsafeConnectionNtlmAuthentication) + { + disconnectResult.AuthenticatedUser = windowsPrincipal; + } + } + } + } + } + } + } + finally + { + if (userContext != null) + { + userContext.Dispose(); + } + } + return true; + } + else + { + // auth incomplete + if (disconnectResult == null) + { + RegisterForDisconnectNotification(env, out disconnectResult); + + // Failed - send 500. + if (disconnectResult == null) + { + context.CloseContext(); + SendError(env, HttpStatusCode.InternalServerError, null); + return false; + } + } + + disconnectResult.Session = context; + + string challenge = package; + if (!String.IsNullOrEmpty(outBlob)) + { + challenge += " " + outBlob; + } + IList challenges = null; + AddChallenge(ref challenges, challenge); + SendError(env, HttpStatusCode.Unauthorized, challenges); + return false; + } + } + + SendError(env, httpError, null); + return false; + } + + private void SetIdentity(IDictionary env, IPrincipal principal, string mutualAuth) + { + env[Constants.ServerUserKey] = principal; + if (!string.IsNullOrWhiteSpace(mutualAuth)) + { + var responseHeaders = env.Get>(Constants.ResponseHeadersKey); + responseHeaders.Append(HttpKnownHeaderNames.WWWAuthenticate, mutualAuth); + } + } + + // For user info only + private void SetServiceName(IDictionary env, string serviceName) + { + if (!string.IsNullOrWhiteSpace(serviceName)) + { + env[Constants.SslSpnKey] = serviceName; + } + } + + [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)] + [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)] + internal static WindowsIdentity CreateWindowsIdentity(IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated) + { + return new WindowsIdentity(userToken, type, acctType, isAuthenticated); + } + + // On a 401 response, set any appropriate challenges + private void Set401Challenges(object state) + { + var env = (IDictionary)state; + var responseHeaders = env.Get>(Constants.ResponseHeadersKey); + + // We use the cached results from the delegates so that we don't have to call them again here. + NTAuthentication newContext; + IList challenges = BuildChallenge(env, AuthenticationSchemes, out newContext, ExtendedProtectionPolicy); + + // null == Anonymous + if (challenges != null) + { + // Digest challenge, keep it alive for 10s - 5min. + if (newContext != null) + { + _digestCache.SaveDigestContext(newContext); + } + + responseHeaders.Append(HttpKnownHeaderNames.WWWAuthenticate, challenges); + } + } + + private static bool IsSecureConnection(IDictionary env) + { + return "https".Equals(env.Get(Constants.RequestSchemeKey, "http"), StringComparison.OrdinalIgnoreCase); + } + + private static bool ScenarioChecksChannelBinding(bool isSecureConnection, ProtectionScenario scenario) + { + return (isSecureConnection && scenario == ProtectionScenario.TransportSelected); + } + + private ChannelBinding GetChannelBinding(IDictionary env, bool isSecureConnection, ExtendedProtectionPolicy policy) + { + if (policy.PolicyEnforcement == PolicyEnforcement.Never) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_cbt_disabled)); + } + return null; + } + + if (!isSecureConnection) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_cbt_http)); + } + return null; + } + + if (!ExtendedProtectionPolicy.OSSupportsExtendedProtection) + { + GlobalLog.Assert(policy.PolicyEnforcement != PolicyEnforcement.Always, "User managed to set PolicyEnforcement.Always when the OS does not support extended protection!"); + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_cbt_platform)); + } + return null; + } + + if (policy.ProtectionScenario == ProtectionScenario.TrustedProxy) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_cbt_trustedproxy)); + } + return null; + } + + ChannelBinding result = env.Get(Constants.SslChannelBindingKey); + if (result == null) + { + // A channel binding object is required. + throw new InvalidOperationException(); + } + + GlobalLog.Assert(result != null, "GetChannelBindingFromTls returned null even though OS supposedly supports Extended Protection"); + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_cbt)); + } + return result; + } + + private bool CheckSpn(NTAuthentication context, bool isSecureConnection, ExtendedProtectionPolicy policy) + { + // Kerberos does SPN check already in ASC + if (context.IsKerberos) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_kerberos)); + } + return true; + } + + // Don't check the SPN if Extended Protection is off or we already checked the CBT + if (policy.PolicyEnforcement == PolicyEnforcement.Never) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_disabled)); + } + return true; + } + + if (ScenarioChecksChannelBinding(isSecureConnection, policy.ProtectionScenario)) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_cbt)); + } + return true; + } + + if (!ExtendedProtectionPolicy.OSSupportsExtendedProtection) + { + GlobalLog.Assert(policy.PolicyEnforcement != PolicyEnforcement.Always, "User managed to set PolicyEnforcement.Always when the OS does not support extended protection!"); + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_platform)); + } + return true; + } + + string clientSpn = context.ClientSpecifiedSpn; + + // An empty SPN is only allowed in the WhenSupported case + if (String.IsNullOrEmpty(clientSpn)) + { + if (policy.PolicyEnforcement == PolicyEnforcement.WhenSupported) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, + SR.GetString(SR.net_log_listener_no_spn_whensupported)); + } + return true; + } + else + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, + SR.GetString(SR.net_log_listener_spn_failed_always)); + } + return false; + } + } + else if (String.Compare(clientSpn, "http/localhost", StringComparison.OrdinalIgnoreCase) == 0) + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_loopback)); + } + + return true; + } + else + { + if (Logging.On) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_spn, clientSpn)); + } + + ServiceNameCollection serviceNames = GetServiceNames(policy); + + bool found = serviceNames.Contains(clientSpn); + + if (Logging.On) + { + if (found) + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_spn_passed)); + } + else + { + Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_spn_failed)); + + if (serviceNames.Count == 0) + { + Logging.PrintWarning(Logging.HttpListener, this, "CheckSpn", + SR.GetString(SR.net_log_listener_spn_failed_empty)); + } + else + { + Logging.PrintInfo(Logging.HttpListener, this, + SR.GetString(SR.net_log_listener_spn_failed_dump)); + + foreach (string serviceName in serviceNames) + { + Logging.PrintInfo(Logging.HttpListener, this, "\t" + serviceName); + } + } + } + } + + return found; + } + } + + private ServiceNameCollection GetServiceNames(ExtendedProtectionPolicy policy) + { + ServiceNameCollection serviceNames; + + if (policy.CustomServiceNames == null) + { + if (_defaultServiceNames.ServiceNames.Count == 0) + { + throw new InvalidOperationException(SR.GetString(SR.net_listener_no_spns)); + } + serviceNames = _defaultServiceNames.ServiceNames; + } + else + { + serviceNames = policy.CustomServiceNames; + } + return serviceNames; + } + + private ContextFlags GetContextFlags(ExtendedProtectionPolicy policy, bool isSecureConnection) + { + ContextFlags result = ContextFlags.Connection; + + if (policy.PolicyEnforcement != PolicyEnforcement.Never) + { + if (policy.PolicyEnforcement == PolicyEnforcement.WhenSupported) + { + result |= ContextFlags.AllowMissingBindings; + } + + if (policy.ProtectionScenario == ProtectionScenario.TrustedProxy) + { + result |= ContextFlags.ProxyBindings; + } + } + + return result; + } + + private static void AddChallenge(ref IList challenges, string challenge) + { + if (challenge != null) + { + challenge = challenge.Trim(); + if (challenge.Length > 0) + { + GlobalLog.Print("HttpListener:AddChallenge() challenge:" + challenge); + if (challenges == null) + { + challenges = new List(4); + } + challenges.Add(challenge); + } + } + } + + private IList BuildChallenge(IDictionary env, AuthTypes authenticationScheme, out NTAuthentication digestContext, + ExtendedProtectionPolicy policy) + { + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() authenticationScheme:" + authenticationScheme.ToString()); + IList challenges = null; + digestContext = null; + + if ((authenticationScheme & AuthTypes.Negotiate) != 0) + { + AddChallenge(ref challenges, NegotiationInfoClass.Negotiate); + } + + if ((authenticationScheme & AuthTypes.Ntlm) != 0) + { + AddChallenge(ref challenges, NegotiationInfoClass.NTLM); + } + + if ((authenticationScheme & AuthTypes.Digest) != 0) + { + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() package:WDigest"); + + NTAuthentication context = null; + try + { + bool isSecureConnection = IsSecureConnection(env); + string outBlob = null; + ChannelBinding binding = GetChannelBinding(env, isSecureConnection, policy); + + context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null, + GetContextFlags(policy, isSecureConnection), binding); + + SecurityStatus statusCode; + outBlob = context.GetOutgoingDigestBlob(null, null, null, Realm, false, false, out statusCode); + GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCode:" + statusCode + " outBlob:[" + outBlob + "]"); + + if (context.IsValidContext) + { + digestContext = context; + _digestCache.SaveDigestContext(digestContext); + } + + AddChallenge(ref challenges, NegotiationInfoClass.Digest + (string.IsNullOrEmpty(outBlob) ? string.Empty : " " + outBlob)); + } + catch (InvalidOperationException) + { + // No CBT available, therefore no digest challenge can be issued. + } + finally + { + if (context != null && digestContext != context) + { + context.CloseContext(); + } + } + } + + return challenges; + } + + private void RegisterForDisconnectNotification(IDictionary env, out DisconnectAsyncResult disconnectResult) + { + object connectionId = env[Constants.ServerConnectionIdKey]; + CancellationToken connectionDisconnect = env.Get(Constants.ServerConnectionDisconnectKey); + if (!connectionDisconnect.CanBeCanceled || connectionDisconnect.IsCancellationRequested) + { + disconnectResult = null; + return; + } + try + { + disconnectResult = new DisconnectAsyncResult(this, connectionId, connectionDisconnect); + } + catch (ObjectDisposedException) + { + // Just disconnected + disconnectResult = null; + return; + } + } + + private void SendError(IDictionary env, HttpStatusCode httpStatusCode, IList challenges) + { + // Send an OWIN HTTP response with the given error status code. + env[Constants.ResponseStatusCodeKey] = (int)httpStatusCode; + + if (challenges != null) + { + var responseHeaders = env.Get>(Constants.ResponseHeadersKey); + responseHeaders.Append(HttpKnownHeaderNames.WWWAuthenticate, challenges); + } + } + + // This only works for context-destroying errors. + private HttpStatusCode HttpStatusFromSecurityStatus(SecurityStatus status) + { + if (IsCredentialFailure(status)) + { + return HttpStatusCode.Unauthorized; + } + if (IsClientFault(status)) + { + return HttpStatusCode.BadRequest; + } + return HttpStatusCode.InternalServerError; + } + + // This only works for context-destroying errors. + private static bool IsCredentialFailure(SecurityStatus error) + { + return error == SecurityStatus.LogonDenied || + error == SecurityStatus.UnknownCredentials || + error == SecurityStatus.NoImpersonation || + error == SecurityStatus.NoAuthenticatingAuthority || + error == SecurityStatus.UntrustedRoot || + error == SecurityStatus.CertExpired || + error == SecurityStatus.SmartcardLogonRequired || + error == SecurityStatus.BadBinding; + } + + // This only works for context-destroying errors. + private static bool IsClientFault(SecurityStatus error) + { + return error == SecurityStatus.InvalidToken || + error == SecurityStatus.CannotPack || + error == SecurityStatus.QopNotSupported || + error == SecurityStatus.NoCredentials || + error == SecurityStatus.MessageAltered || + error == SecurityStatus.OutOfSequence || + error == SecurityStatus.IncompleteMessage || + error == SecurityStatus.IncompleteCredentials || + error == SecurityStatus.WrongPrincipal || + error == SecurityStatus.TimeSkew || + error == SecurityStatus.IllegalMessage || + error == SecurityStatus.CertUnknown || + error == SecurityStatus.AlgorithmMismatch || + error == SecurityStatus.SecurityQosFailed || + error == SecurityStatus.UnsupportedPreauth; + } + } +} diff --git a/src/Microsoft.AspNet.Security.Windows/packages.config b/src/Microsoft.AspNet.Security.Windows/packages.config new file mode 100644 index 0000000000..7432196421 --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Windows/project.json b/src/Microsoft.AspNet.Security.Windows/project.json new file mode 100644 index 0000000000..3fe6a340df --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/project.json @@ -0,0 +1,14 @@ +{ + "version": "0.1-alpha-*", + "dependencies": { + }, + "compilationOptions" : { "allowUnsafe": true }, + "configurations": + { + "net45" : { + "dependencies": { + "Owin": "1.0" + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/AsyncAcceptContext.cs b/src/Microsoft.AspNet.Server.WebListener/AsyncAcceptContext.cs new file mode 100644 index 0000000000..a929f8a854 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/AsyncAcceptContext.cs @@ -0,0 +1,224 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal unsafe class AsyncAcceptContext : IAsyncResult, IDisposable + { + internal static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(IOWaitCallback); + + private TaskCompletionSource _tcs; + private OwinWebListener _server; + private NativeRequestContext _nativeRequestContext; + + internal AsyncAcceptContext(OwinWebListener server) + { + _server = server; + _tcs = new TaskCompletionSource(); + _nativeRequestContext = new NativeRequestContext(this); + } + + internal Task Task + { + get + { + return _tcs.Task; + } + } + + private TaskCompletionSource Tcs + { + get + { + return _tcs; + } + } + + private OwinWebListener Server + { + get + { + return _server; + } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting to callback")] + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by callback")] + private static void IOCompleted(AsyncAcceptContext asyncResult, uint errorCode, uint numBytes) + { + bool complete = false; + try + { + if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) + { + asyncResult.Tcs.TrySetException(new WebListenerException((int)errorCode)); + complete = true; + } + else + { + OwinWebListener server = asyncResult.Server; + if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + // at this point we have received an unmanaged HTTP_REQUEST and memoryBlob + // points to it we need to hook up our authentication handling code here. + bool stoleBlob = false; + try + { + if (server.ValidateRequest(asyncResult._nativeRequestContext)) + { + stoleBlob = true; + RequestContext requestContext = new RequestContext(server, asyncResult._nativeRequestContext); + asyncResult.Tcs.TrySetResult(requestContext); + complete = true; + } + } + finally + { + if (stoleBlob) + { + // The request has been handed to the user, which means this code can't reuse the blob. Reset it here. + asyncResult._nativeRequestContext = complete ? null : new NativeRequestContext(asyncResult); + } + else + { + asyncResult._nativeRequestContext.Reset(0, 0); + } + } + } + else + { + asyncResult._nativeRequestContext.Reset(asyncResult._nativeRequestContext.RequestBlob->RequestId, numBytes); + } + + // We need to issue a new request, either because auth failed, or because our buffer was too small the first time. + if (!complete) + { + uint statusCode = asyncResult.QueueBeginGetContext(); + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + // someother bad error, possible(?) return values are: + // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED + asyncResult.Tcs.TrySetException(new WebListenerException((int)statusCode)); + complete = true; + } + } + if (!complete) + { + return; + } + } + + if (complete) + { + asyncResult.Dispose(); + } + } + catch (Exception exception) + { + // Logged by caller + asyncResult.Tcs.TrySetException(exception); + asyncResult.Dispose(); + } + } + + private static unsafe void IOWaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) + { + // take the ListenerAsyncResult object from the state + Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); + AsyncAcceptContext asyncResult = (AsyncAcceptContext)callbackOverlapped.AsyncResult; + + IOCompleted(asyncResult, errorCode, numBytes); + } + + internal uint QueueBeginGetContext() + { + uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; + bool retry; + do + { + retry = false; + uint bytesTransferred = 0; + statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest( + Server.RequestQueueHandle, + _nativeRequestContext.RequestBlob->RequestId, + (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, + _nativeRequestContext.RequestBlob, + _nativeRequestContext.Size, + &bytesTransferred, + _nativeRequestContext.NativeOverlapped); + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER && _nativeRequestContext.RequestBlob->RequestId != 0) + { + // we might get this if somebody stole our RequestId, + // set RequestId to 0 and start all over again with the buffer we just allocated + // BUGBUG: how can someone steal our request ID? seems really bad and in need of fix. + _nativeRequestContext.RequestBlob->RequestId = 0; + retry = true; + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) + { + // the buffer was not big enough to fit the headers, we need + // to read the RequestId returned, allocate a new buffer of the required size + _nativeRequestContext.Reset(_nativeRequestContext.RequestBlob->RequestId, bytesTransferred); + retry = true; + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS + && OwinWebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + IOCompleted(this, statusCode, bytesTransferred); + } + } + while (retry); + return statusCode; + } + + public object AsyncState + { + get { return _tcs.Task.AsyncState; } + } + + public WaitHandle AsyncWaitHandle + { + get { return ((IAsyncResult)_tcs.Task).AsyncWaitHandle; } + } + + public bool CompletedSynchronously + { + get { return ((IAsyncResult)_tcs.Task).CompletedSynchronously; } + } + + public bool IsCompleted + { + get { return _tcs.Task.IsCompleted; } + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_nativeRequestContext != null) + { + _nativeRequestContext.ReleasePins(); + _nativeRequestContext.Dispose(); + } + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationManager.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationManager.cs new file mode 100644 index 0000000000..9fa737049a --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationManager.cs @@ -0,0 +1,129 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Server.WebListener +{ + // See the native HTTP_SERVER_AUTHENTICATION_INFO structure documentation for additional information. + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364638(v=vs.85).aspx + + /// + /// Exposes the Http.Sys authentication configurations. + /// + public sealed class AuthenticationManager + { +#if NET45 + private static readonly int AuthInfoSize = + Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO)); +#else + private static readonly int AuthInfoSize = + Marshal.SizeOf(); +#endif + + private OwinWebListener _server; + AuthenticationType _authTypes; + + internal AuthenticationManager(OwinWebListener context) + { + _server = context; + _authTypes = AuthenticationType.None; + } + + #region Properties + + public AuthenticationType AuthenticationTypes + { + get + { + return _authTypes; + } + set + { + _authTypes = value; + SetServerSecurity(); + } + } + + #endregion Properties + + private unsafe void SetServerSecurity() + { + UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO authInfo = + new UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO(); + + authInfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + authInfo.AuthSchemes = (UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES)_authTypes; + + // TODO: + // NTLM auth sharing (on by default?) DisableNTLMCredentialCaching + // Kerberos auth sharing (off by default?) HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING + // Mutual Auth - ReceiveMutualAuth + // Digest domain and realm - HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS + // Basic realm - HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS + + IntPtr infoptr = new IntPtr(&authInfo); + + _server.SetUrlGroupProperty( + UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, + infoptr, (uint)AuthInfoSize); + } + + internal void SetAuthenticationChallenge(Response response) + { + if (_authTypes == AuthenticationType.None) + { + return; + } + + IList challenges = new List(); + + // Order by strength. + if ((_authTypes & AuthenticationType.Kerberos) == AuthenticationType.Kerberos) + { + challenges.Add("Kerberos"); + } + if ((_authTypes & AuthenticationType.Negotiate) == AuthenticationType.Negotiate) + { + challenges.Add("Negotiate"); + } + if ((_authTypes & AuthenticationType.Ntlm) == AuthenticationType.Ntlm) + { + challenges.Add("NTLM"); + } + if ((_authTypes & AuthenticationType.Digest) == AuthenticationType.Digest) + { + // TODO: + throw new NotImplementedException("Digest challenge generation has not been implemented."); + // challenges.Add("Digest"); + } + if ((_authTypes & AuthenticationType.Basic) == AuthenticationType.Basic) + { + // TODO: Realm + challenges.Add("Basic"); + } + + // Append to the existing header, if any. Some clients (IE, Chrome) require each challenges to be sent on their own line/header. + string[] oldValues; + string[] newValues; + if (response.Headers.TryGetValue(HttpKnownHeaderNames.WWWAuthenticate, out oldValues)) + { + newValues = new string[oldValues.Length + challenges.Count]; + Array.Copy(oldValues, newValues, oldValues.Length); + challenges.CopyTo(newValues, oldValues.Length); + } + else + { + newValues = new string[challenges.Count]; + challenges.CopyTo(newValues, 0); + } + response.Headers[HttpKnownHeaderNames.WWWAuthenticate] = newValues; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationTypes.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationTypes.cs new file mode 100644 index 0000000000..2e47212706 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationTypes.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + [Flags] + public enum AuthenticationType + { + None = 0x0, + Basic = 0x1, + Digest = 0x2, + Ntlm = 0x4, + Negotiate = 0x8, + Kerberos = 0x10, + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/Constants.cs b/src/Microsoft.AspNet.Server.WebListener/Constants.cs new file mode 100644 index 0000000000..53e3325471 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/Constants.cs @@ -0,0 +1,63 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class Constants + { + internal const string VersionKey = "owin.Version"; + internal const string OwinVersion = "1.0"; + internal const string CallCancelledKey = "owin.CallCancelled"; + + internal const string ServerCapabilitiesKey = "server.Capabilities"; + + internal const string RequestBodyKey = "owin.RequestBody"; + internal const string RequestHeadersKey = "owin.RequestHeaders"; + internal const string RequestSchemeKey = "owin.RequestScheme"; + internal const string RequestMethodKey = "owin.RequestMethod"; + internal const string RequestPathBaseKey = "owin.RequestPathBase"; + internal const string RequestPathKey = "owin.RequestPath"; + internal const string RequestQueryStringKey = "owin.RequestQueryString"; + internal const string HttpRequestProtocolKey = "owin.RequestProtocol"; + + internal const string HttpResponseProtocolKey = "owin.ResponseProtocol"; + internal const string ResponseStatusCodeKey = "owin.ResponseStatusCode"; + internal const string ResponseReasonPhraseKey = "owin.ResponseReasonPhrase"; + internal const string ResponseHeadersKey = "owin.ResponseHeaders"; + internal const string ResponseBodyKey = "owin.ResponseBody"; + + internal const string ClientCertifiateKey = "ssl.ClientCertificate"; + + internal const string RemoteIpAddressKey = "server.RemoteIpAddress"; + internal const string RemotePortKey = "server.RemotePort"; + internal const string LocalIpAddressKey = "server.LocalIpAddress"; + internal const string LocalPortKey = "server.LocalPort"; + internal const string IsLocalKey = "server.IsLocal"; + internal const string ServerOnSendingHeadersKey = "server.OnSendingHeaders"; + internal const string ServerLoggerFactoryKey = "server.LoggerFactory"; + + internal const string OpaqueVersionKey = "opaque.Version"; + internal const string OpaqueVersion = "1.0"; + internal const string OpaqueFuncKey = "opaque.Upgrade"; + internal const string OpaqueStreamKey = "opaque.Stream"; + internal const string OpaqueCallCancelledKey = "opaque.CallCancelled"; + + internal const string SendFileVersionKey = "sendfile.Version"; + internal const string SendFileVersion = "1.0"; + internal const string SendFileSupportKey = "sendfile.Support"; + internal const string SendFileConcurrencyKey = "sendfile.Concurrency"; + internal const string Overlapped = "Overlapped"; + + internal const string HttpScheme = "http"; + internal const string HttpsScheme = "https"; + internal const string SchemeDelimiter = "://"; + + internal static Version V1_0 = new Version(1, 0); + internal static Version V1_1 = new Version(1, 1); + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/CustomDictionary.xml b/src/Microsoft.AspNet.Server.WebListener/CustomDictionary.xml new file mode 100644 index 0000000000..78a76142f7 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/CustomDictionary.xml @@ -0,0 +1,10 @@ + + + + + Owin + + + + + diff --git a/src/Microsoft.AspNet.Server.WebListener/DictionaryExtensions.cs b/src/Microsoft.AspNet.Server.WebListener/DictionaryExtensions.cs new file mode 100644 index 0000000000..a1a6e3577a --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/DictionaryExtensions.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Linq; +using System.Text; + +namespace System.Collections.Generic +{ + internal static class DictionaryExtensions + { + internal static void Append(this IDictionary dictionary, string key, string value) + { + string[] orriginalValues; + if (dictionary.TryGetValue(key, out orriginalValues)) + { + string[] newValues = new string[orriginalValues.Length + 1]; + orriginalValues.CopyTo(newValues, 0); + newValues[newValues.Length - 1] = value; + dictionary[key] = newValues; + } + else + { + dictionary[key] = new string[] { value }; + } + } + + internal static string Get(this IDictionary dictionary, string key) + { + string[] values; + if (dictionary.TryGetValue(key, out values)) + { + return string.Join(", ", values); + } + return null; + } + + internal static T Get(this IDictionary dictionary, string key, T fallback = default(T)) + { + object values; + if (dictionary.TryGetValue(key, out values)) + { + return (T)values; + } + return fallback; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/GlobalSuppressions.cs b/src/Microsoft.AspNet.Server.WebListener/GlobalSuppressions.cs new file mode 100644 index 0000000000000000000000000000000000000000..2b0ddbdbf4a6b419d14999f431a6e44ef4126bf5 GIT binary patch literal 1926 zcmd6o-HX#u5XI+N@PD}EX$8BhKI*Pe6u)3a=&~TP4{2K4Xw#HUD)gUMe`jvPO`Gof z63EBgxie?ZnYsD*_rfkL*yvGRPwfe)gzM4@t8HUDySLI7wzL-OPu^EHw=2u+BX6}$ zE$2D0ExsFk=hkqQtgLyS6Q#j7c(e+S9Q)4qU*lD>7 z(l6}4w_f#(l_{!3=4LPuY>ZA)c85pY+rnqC3Tw$)yMKm(_SgF!$mtqIN;srN>&#E- zm)89P&!wvrxT}BkR4=W_BQ4~i%<_v!)MvH*Vzt29*XrBB%7_?qS5%5O5AW*SGZJ*CO|!vkS^FM-!-;=oyxYsUa+p2DOeX{DURkqwKeQ|a$7yA_v z6eq`LZqGf&&g1G`s};HlwZ4U~=&_OT+;|;1`IJ%7PjfM3x|?^!PZKjDkJKsbH+JbF zwj$bw_)&LtNm@;4G@TFiSUf+rL~p^UteWE3Zyma9&~Z8i;<*!ZXTGyzxQ{iV$n3M@ zJAHBm`#@H8Pu62J*muxuK{azm)gS7KHGYTsMW#=)tT{aH=#J+&Uu$w`_B4I5yM +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class Helpers + { + internal static Task CompletedTask() + { + return Task.FromResult(null); + } + + internal static ConfiguredTaskAwaitable SupressContext(this Task task) + { + return task.ConfigureAwait(continueOnCapturedContext: false); + } + + internal static ConfiguredTaskAwaitable SupressContext(this Task task) + { + return task.ConfigureAwait(continueOnCapturedContext: false); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs new file mode 100644 index 0000000000..a6513df571 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.Globalization; + +namespace Microsoft.AspNet.Server.WebListener +{ + using LoggerFactoryFunc = Func, bool>>; + using LoggerFunc = Func, bool>; + + internal static class LogHelper + { + private static readonly Func LogState = + (state, error) => Convert.ToString(state, CultureInfo.CurrentCulture); + + private static readonly Func LogStateAndError = + (state, error) => string.Format(CultureInfo.CurrentCulture, "{0}\r\n{1}", state, error); + + internal static LoggerFunc CreateLogger(LoggerFactoryFunc factory, Type type) + { + if (factory == null) + { + return null; + } + + return factory(type.FullName); + } + + internal static void LogInfo(LoggerFunc logger, string data) + { + if (logger == null) + { + Debug.WriteLine(data); + } + else + { + logger(TraceEventType.Information, 0, data, null, LogState); + } + } + + internal static void LogVerbose(LoggerFunc logger, string data) + { + if (logger == null) + { + Debug.WriteLine(data); + } + else + { + logger(TraceEventType.Verbose, 0, data, null, LogState); + } + } + + internal static void LogException(LoggerFunc logger, string location, Exception exception) + { + if (logger == null) + { + Debug.WriteLine(exception); + } + else + { + logger(TraceEventType.Error, 0, location, exception, LogStateAndError); + } + } + + internal static void LogError(LoggerFunc logger, string location, string message) + { + if (logger == null) + { + Debug.WriteLine(message); + } + else + { + logger(TraceEventType.Error, 0, location + ": " + message, null, LogState); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/AddressFamily.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/AddressFamily.cs new file mode 100644 index 0000000000..5f78516900 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/AddressFamily.cs @@ -0,0 +1,172 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.Server.WebListener +{ + /// + /// + /// Specifies the address families that an instance of the + /// class can use. + /// + /// + internal enum AddressFamily + { + /// + /// [To be supplied.] + /// + Unknown = -1, // Unknown + + /// + /// [To be supplied.] + /// + Unspecified = 0, // unspecified + + /// + /// [To be supplied.] + /// + Unix = 1, // local to host (pipes, portals) + + /// + /// [To be supplied.] + /// + InterNetwork = 2, // internetwork: UDP, TCP, etc. + + /// + /// [To be supplied.] + /// + ImpLink = 3, // arpanet imp addresses + + /// + /// [To be supplied.] + /// + Pup = 4, // pup protocols: e.g. BSP + + /// + /// [To be supplied.] + /// + Chaos = 5, // mit CHAOS protocols + + /// + /// [To be supplied.] + /// + NS = 6, // XEROX NS protocols + + /// + /// [To be supplied.] + /// + Ipx = NS, // IPX and SPX + + /// + /// [To be supplied.] + /// + Iso = 7, // ISO protocols + + /// + /// [To be supplied.] + /// + Osi = Iso, // OSI is ISO + + /// + /// [To be supplied.] + /// + Ecma = 8, // european computer manufacturers + + /// + /// [To be supplied.] + /// + DataKit = 9, // datakit protocols + + /// + /// [To be supplied.] + /// + Ccitt = 10, // CCITT protocols, X.25 etc + + /// + /// [To be supplied.] + /// + Sna = 11, // IBM SNA + + /// + /// [To be supplied.] + /// + DecNet = 12, // DECnet + + /// + /// [To be supplied.] + /// + DataLink = 13, // Direct data link interface + + /// + /// [To be supplied.] + /// + Lat = 14, // LAT + + /// + /// [To be supplied.] + /// + HyperChannel = 15, // NSC Hyperchannel + + /// + /// [To be supplied.] + /// + AppleTalk = 16, // AppleTalk + + /// + /// [To be supplied.] + /// + NetBios = 17, // NetBios-style addresses + + /// + /// [To be supplied.] + /// + VoiceView = 18, // VoiceView + + /// + /// [To be supplied.] + /// + FireFox = 19, // FireFox + + /// + /// [To be supplied.] + /// + Banyan = 21, // Banyan + + /// + /// [To be supplied.] + /// + Atm = 22, // Native ATM Services + + /// + /// [To be supplied.] + /// + InterNetworkV6 = 23, // Internetwork Version 6 + + /// + /// [To be supplied.] + /// + Cluster = 24, // Microsoft Wolfpack + + /// + /// [To be supplied.] + /// + Ieee12844 = 25, // IEEE 1284.4 WG AF + + /// + /// [To be supplied.] + /// + Irda = 26, // IrDA + + /// + /// [To be supplied.] + /// + NetworkDesigners = 28, // Network Designers OSI & gateway enabled protocols + + /// + /// [To be supplied.] + /// + Max = 29, // Max + }; // enum AddressFamily +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ComNetOS.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ComNetOS.cs new file mode 100644 index 0000000000..80e2719065 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ComNetOS.cs @@ -0,0 +1,26 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class ComNetOS + { + // Minimum support for Windows 7 is assumed. + internal static readonly bool IsWin8orLater; + + static ComNetOS() + { +#if NET45 + var win8Version = new Version(6, 2); + IsWin8orLater = (Environment.OSVersion.Version >= win8Version); +#else + IsWin8orLater = true; +#endif + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ContextAttribute.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ContextAttribute.cs new file mode 100644 index 0000000000..a3440bc7a3 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ContextAttribute.cs @@ -0,0 +1,56 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Server.WebListener +{ + internal enum ContextAttribute + { + // look into and + Sizes = 0x00, + Names = 0x01, + Lifespan = 0x02, + DceInfo = 0x03, + StreamSizes = 0x04, + // KeyInfo = 0x05, must not be used, see ConnectionInfo instead + Authority = 0x06, + // SECPKG_ATTR_PROTO_INFO = 7, + // SECPKG_ATTR_PASSWORD_EXPIRY = 8, + // SECPKG_ATTR_SESSION_KEY = 9, + PackageInfo = 0x0A, + // SECPKG_ATTR_USER_FLAGS = 11, + NegotiationInfo = 0x0C, + // SECPKG_ATTR_NATIVE_NAMES = 13, + // SECPKG_ATTR_FLAGS = 14, + // SECPKG_ATTR_USE_VALIDATED = 15, + // SECPKG_ATTR_CREDENTIAL_NAME = 16, + // SECPKG_ATTR_TARGET_INFORMATION = 17, + // SECPKG_ATTR_ACCESS_TOKEN = 18, + // SECPKG_ATTR_TARGET = 19, + // SECPKG_ATTR_AUTHENTICATION_ID = 20, + UniqueBindings = 0x19, + EndpointBindings = 0x1A, + ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27 + RemoteCertificate = 0x53, + LocalCertificate = 0x54, + RootStore = 0x55, + IssuerListInfoEx = 0x59, + ConnectionInfo = 0x5A, + // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock + // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr + // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo + // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData + // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates + // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy + // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult + // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group + // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo + // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo + // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo + // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures + // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT + UiInfo = 0x68, // sets SEcPkgContext_UiInfo + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpRequestQueueV2Handle.cs new file mode 100644 index 0000000000..ad9ae1d391 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpRequestQueueV2Handle.cs @@ -0,0 +1,25 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Server.WebListener +{ + // This class is a wrapper for Http.sys V2 request queue handle. + internal sealed class HttpRequestQueueV2Handle : SafeHandleZeroOrMinusOneIsInvalid + { + private HttpRequestQueueV2Handle() + : base(true) + { + } + + protected override bool ReleaseHandle() + { + return (UnsafeNclNativeMethods.SafeNetHandles.HttpCloseRequestQueue(handle) == + UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpServerSessionHandle.cs new file mode 100644 index 0000000000..65c0506f5c --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpServerSessionHandle.cs @@ -0,0 +1,48 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Threading; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal sealed class HttpServerSessionHandle : CriticalHandleZeroOrMinusOneIsInvalid + { + private int disposed; + private ulong serverSessionId; + + internal HttpServerSessionHandle(ulong id) + : base() + { + serverSessionId = id; + + // This class uses no real handle so we need to set a dummy handle. Otherwise, IsInvalid always remains + // true. + + SetHandle(new IntPtr(1)); + } + + internal ulong DangerousGetServerSessionId() + { + return serverSessionId; + } + + protected override bool ReleaseHandle() + { + if (!IsInvalid) + { + if (Interlocked.Increment(ref disposed) == 1) + { + // Closing server session also closes all open url groups under that server session. + return (UnsafeNclNativeMethods.HttpApi.HttpCloseServerSession(serverSessionId) == + UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); + } + } + return true; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysRequestHeader.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysRequestHeader.cs new file mode 100644 index 0000000000..1202ab2c80 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysRequestHeader.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.Server.WebListener +{ + internal enum HttpSysRequestHeader + { + CacheControl = 0, // general-header [section 4.5] + Connection = 1, // general-header [section 4.5] + Date = 2, // general-header [section 4.5] + KeepAlive = 3, // general-header [not in rfc] + Pragma = 4, // general-header [section 4.5] + Trailer = 5, // general-header [section 4.5] + TransferEncoding = 6, // general-header [section 4.5] + Upgrade = 7, // general-header [section 4.5] + Via = 8, // general-header [section 4.5] + Warning = 9, // general-header [section 4.5] + Allow = 10, // entity-header [section 7.1] + ContentLength = 11, // entity-header [section 7.1] + ContentType = 12, // entity-header [section 7.1] + ContentEncoding = 13, // entity-header [section 7.1] + ContentLanguage = 14, // entity-header [section 7.1] + ContentLocation = 15, // entity-header [section 7.1] + ContentMd5 = 16, // entity-header [section 7.1] + ContentRange = 17, // entity-header [section 7.1] + Expires = 18, // entity-header [section 7.1] + LastModified = 19, // entity-header [section 7.1] + + Accept = 20, // request-header [section 5.3] + AcceptCharset = 21, // request-header [section 5.3] + AcceptEncoding = 22, // request-header [section 5.3] + AcceptLanguage = 23, // request-header [section 5.3] + Authorization = 24, // request-header [section 5.3] + Cookie = 25, // request-header [not in rfc] + Expect = 26, // request-header [section 5.3] + From = 27, // request-header [section 5.3] + Host = 28, // request-header [section 5.3] + IfMatch = 29, // request-header [section 5.3] + IfModifiedSince = 30, // request-header [section 5.3] + IfNoneMatch = 31, // request-header [section 5.3] + IfRange = 32, // request-header [section 5.3] + IfUnmodifiedSince = 33, // request-header [section 5.3] + MaxForwards = 34, // request-header [section 5.3] + ProxyAuthorization = 35, // request-header [section 5.3] + Referer = 36, // request-header [section 5.3] + Range = 37, // request-header [section 5.3] + Te = 38, // request-header [section 5.3] + Translate = 39, // request-header [webDAV, not in rfc 2518] + UserAgent = 40, // request-header [section 5.3] + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysResponseHeader.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysResponseHeader.cs new file mode 100644 index 0000000000..0c7707e943 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysResponseHeader.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.Server.WebListener +{ + internal enum HttpSysResponseHeader + { + CacheControl = 0, // general-header [section 4.5] + Connection = 1, // general-header [section 4.5] + Date = 2, // general-header [section 4.5] + KeepAlive = 3, // general-header [not in rfc] + Pragma = 4, // general-header [section 4.5] + Trailer = 5, // general-header [section 4.5] + TransferEncoding = 6, // general-header [section 4.5] + Upgrade = 7, // general-header [section 4.5] + Via = 8, // general-header [section 4.5] + Warning = 9, // general-header [section 4.5] + Allow = 10, // entity-header [section 7.1] + ContentLength = 11, // entity-header [section 7.1] + ContentType = 12, // entity-header [section 7.1] + ContentEncoding = 13, // entity-header [section 7.1] + ContentLanguage = 14, // entity-header [section 7.1] + ContentLocation = 15, // entity-header [section 7.1] + ContentMd5 = 16, // entity-header [section 7.1] + ContentRange = 17, // entity-header [section 7.1] + Expires = 18, // entity-header [section 7.1] + LastModified = 19, // entity-header [section 7.1] + + AcceptRanges = 20, // response-header [section 6.2] + Age = 21, // response-header [section 6.2] + ETag = 22, // response-header [section 6.2] + Location = 23, // response-header [section 6.2] + ProxyAuthenticate = 24, // response-header [section 6.2] + RetryAfter = 25, // response-header [section 6.2] + Server = 26, // response-header [section 6.2] + SetCookie = 27, // response-header [not in rfc] + Vary = 28, // response-header [section 6.2] + WwwAuthenticate = 29, // response-header [section 6.2] + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysSettings.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysSettings.cs new file mode 100644 index 0000000000..98067e6fd6 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysSettings.cs @@ -0,0 +1,125 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Security; +#if NET45 +using Microsoft.Win32; +#endif + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class HttpSysSettings + { +#if NET45 + private const string HttpSysParametersKey = @"System\CurrentControlSet\Services\HTTP\Parameters"; +#endif + private const bool EnableNonUtf8Default = true; + private const bool FavorUtf8Default = true; + private const string EnableNonUtf8Name = "EnableNonUtf8"; + private const string FavorUtf8Name = "FavorUtf8"; + + private static volatile bool enableNonUtf8 = EnableNonUtf8Default; + private static volatile bool favorUtf8 = FavorUtf8Default; + + static HttpSysSettings() + { + ReadHttpSysRegistrySettings(); + } + + internal static bool EnableNonUtf8 + { + get { return enableNonUtf8; } + } + + internal static bool FavorUtf8 + { + get { return favorUtf8; } + } + + private static void ReadHttpSysRegistrySettings() +#if !NET45 + { + } +#else + { + try + { + RegistryKey httpSysParameters = Registry.LocalMachine.OpenSubKey(HttpSysParametersKey); + + if (httpSysParameters == null) + { + LogWarning("ReadHttpSysRegistrySettings", "The Http.Sys registry key is null.", + HttpSysParametersKey); + } + else + { + using (httpSysParameters) + { + enableNonUtf8 = ReadRegistryValue(httpSysParameters, EnableNonUtf8Name, EnableNonUtf8Default); + favorUtf8 = ReadRegistryValue(httpSysParameters, FavorUtf8Name, FavorUtf8Default); + } + } + } + catch (SecurityException e) + { + LogRegistryException("ReadHttpSysRegistrySettings", e); + } + catch (ObjectDisposedException e) + { + LogRegistryException("ReadHttpSysRegistrySettings", e); + } + } + + private static bool ReadRegistryValue(RegistryKey key, string valueName, bool defaultValue) + { + Debug.Assert(key != null, "'key' must not be null"); + + try + { + if (key.GetValue(valueName) != null && key.GetValueKind(valueName) == RegistryValueKind.DWord) + { + // At this point we know the Registry value exists and it must be valid (any DWORD value + // can be converted to a bool). + return Convert.ToBoolean(key.GetValue(valueName), CultureInfo.InvariantCulture); + } + } + catch (UnauthorizedAccessException e) + { + LogRegistryException("ReadRegistryValue", e); + } + catch (IOException e) + { + LogRegistryException("ReadRegistryValue", e); + } + catch (SecurityException e) + { + LogRegistryException("ReadRegistryValue", e); + } + catch (ObjectDisposedException e) + { + LogRegistryException("ReadRegistryValue", e); + } + + return defaultValue; + } + + private static void LogRegistryException(string methodName, Exception e) + { + LogWarning(methodName, "Unable to access the Http.Sys registry value.", HttpSysParametersKey, e); + } + + private static void LogWarning(string methodName, string message, params object[] args) + { + // TODO: log + // Logging.PrintWarning(Logging.HttpListener, typeof(HttpSysSettings), methodName, SR.GetString(message, args)); + } +#endif + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/IntPtrHelper.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/IntPtrHelper.cs new file mode 100644 index 0000000000..87ee72ce34 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/IntPtrHelper.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class IntPtrHelper + { + internal static IntPtr Add(IntPtr a, int b) + { + return (IntPtr)((long)a + (long)b); + } + + internal static long Subtract(IntPtr a, IntPtr b) + { + return ((long)a - (long)b); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/NclUtilities.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/NclUtilities.cs new file mode 100644 index 0000000000..4e74a95560 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/NclUtilities.cs @@ -0,0 +1,25 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class NclUtilities + { + internal static bool HasShutdownStarted + { + get + { + return Environment.HasShutdownStarted +#if NET45 + || AppDomain.CurrentDomain.IsFinalizingForUnload() +#endif + ; + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SSPIHandle.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SSPIHandle.cs new file mode 100644 index 0000000000..6089860776 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SSPIHandle.cs @@ -0,0 +1,34 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Server.WebListener +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct SSPIHandle + { + private IntPtr handleHi; + private IntPtr handleLo; + + public bool IsZero + { + get { return handleHi == IntPtr.Zero && handleLo == IntPtr.Zero; } + } + + internal void SetToInvalid() + { + handleHi = IntPtr.Zero; + handleLo = IntPtr.Zero; + } + + public override string ToString() + { + return handleHi.ToString("x") + ":" + handleLo.ToString("x"); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLoadLibrary.cs new file mode 100644 index 0000000000..998fbe014a --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLoadLibrary.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid + { + private const string KERNEL32 = "kernel32.dll"; + + public static readonly SafeLoadLibrary Zero = new SafeLoadLibrary(false); + + private SafeLoadLibrary() + : base(true) + { + } + + private SafeLoadLibrary(bool ownsHandle) + : base(ownsHandle) + { + } + + public static unsafe SafeLoadLibrary LoadLibraryEx(string library) + { + SafeLoadLibrary result = UnsafeNclNativeMethods.SafeNetHandles.LoadLibraryExW(library, null, 0); + if (result.IsInvalid) + { + result.SetHandleAsInvalid(); + } + return result; + } + + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SafeNetHandles.FreeLibrary(handle); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFree.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFree.cs new file mode 100644 index 0000000000..ad35b83ff0 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFree.cs @@ -0,0 +1,46 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid + { + private const int LMEM_FIXED = 0; + private const int NULL = 0; + + // This returned handle cannot be modified by the application. + public static SafeLocalFree Zero = new SafeLocalFree(false); + + private SafeLocalFree() + : base(true) + { + } + + private SafeLocalFree(bool ownsHandle) + : base(ownsHandle) + { + } + + public static SafeLocalFree LocalAlloc(int cb) + { + SafeLocalFree result = UnsafeNclNativeMethods.SafeNetHandles.LocalAlloc(LMEM_FIXED, (UIntPtr)cb); + if (result.IsInvalid) + { + result.SetHandleAsInvalid(); + throw new OutOfMemoryException(); + } + return result; + } + + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFreeChannelBinding.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFreeChannelBinding.cs new file mode 100644 index 0000000000..66124161ca --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Security.Authentication.ExtendedProtection; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class SafeLocalFreeChannelBinding : ChannelBinding + { + private const int LMEM_FIXED = 0; + private int size; + + public override int Size + { + get { return size; } + } + + public static SafeLocalFreeChannelBinding LocalAlloc(int cb) + { + SafeLocalFreeChannelBinding result; + + result = UnsafeNclNativeMethods.SafeNetHandles.LocalAllocChannelBinding(LMEM_FIXED, (UIntPtr)cb); + if (result.IsInvalid) + { + result.SetHandleAsInvalid(); + throw new OutOfMemoryException(); + } + + result.size = cb; + return result; + } + + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalMemHandle.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalMemHandle.cs new file mode 100644 index 0000000000..6bc76f512f --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalMemHandle.cs @@ -0,0 +1,30 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid + { + internal SafeLocalMemHandle() + : base(true) + { + } + + internal SafeLocalMemHandle(IntPtr existingHandle, bool ownsHandle) + : base(ownsHandle) + { + SetHandle(existingHandle); + } + + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeNativeOverlapped.cs new file mode 100644 index 0000000000..c36466ec84 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeNativeOverlapped.cs @@ -0,0 +1,68 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class SafeNativeOverlapped : SafeHandle + { + internal static readonly SafeNativeOverlapped Zero = new SafeNativeOverlapped(); + + internal SafeNativeOverlapped() + : this(IntPtr.Zero) + { + } + + internal unsafe SafeNativeOverlapped(NativeOverlapped* handle) + : this((IntPtr)handle) + { + } + + internal SafeNativeOverlapped(IntPtr handle) + : base(IntPtr.Zero, true) + { + SetHandle(handle); + } + + public override bool IsInvalid + { + get { return handle == IntPtr.Zero; } + } + + public void ReinitializeNativeOverlapped() + { + IntPtr handleSnapshot = handle; + + if (handleSnapshot != IntPtr.Zero) + { + unsafe + { + ((NativeOverlapped*)handleSnapshot)->InternalHigh = IntPtr.Zero; + ((NativeOverlapped*)handleSnapshot)->InternalLow = IntPtr.Zero; + ((NativeOverlapped*)handleSnapshot)->EventHandle = IntPtr.Zero; + } + } + } + + protected override bool ReleaseHandle() + { + IntPtr oldHandle = Interlocked.Exchange(ref handle, IntPtr.Zero); + // Do not call free durring AppDomain shutdown, there may be an outstanding operation. + // Overlapped will take care calling free when the native callback completes. + if (oldHandle != IntPtr.Zero && !NclUtilities.HasShutdownStarted) + { + unsafe + { + Overlapped.Free((NativeOverlapped*)oldHandle); + } + } + return true; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SchProtocols.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SchProtocols.cs new file mode 100644 index 0000000000..be1d240cd2 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SchProtocols.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.Server.WebListener +{ + using System; + using System.Globalization; + using System.Runtime.InteropServices; + + // From Schannel.h + [Flags] + internal enum SchProtocols + { + Zero = 0, + PctClient = 0x00000002, + PctServer = 0x00000001, + Pct = (PctClient | PctServer), + Ssl2Client = 0x00000008, + Ssl2Server = 0x00000004, + Ssl2 = (Ssl2Client | Ssl2Server), + Ssl3Client = 0x00000020, + Ssl3Server = 0x00000010, + Ssl3 = (Ssl3Client | Ssl3Server), + Tls10Client = 0x00000080, + Tls10Server = 0x00000040, + Tls10 = (Tls10Client | Tls10Server), + Tls11Client = 0x00000200, + Tls11Server = 0x00000100, + Tls11 = (Tls11Client | Tls11Server), + Tls12Client = 0x00000800, + Tls12Server = 0x00000400, + Tls12 = (Tls12Client | Tls12Server), + Ssl3Tls = (Ssl3 | Tls10), + UniClient = unchecked((int)0x80000000), + UniServer = 0x40000000, + Unified = (UniClient | UniServer), + ClientMask = (PctClient | Ssl2Client | Ssl3Client | Tls10Client | Tls11Client | Tls12Client | UniClient), + ServerMask = (PctServer | Ssl2Server | Ssl3Server | Tls10Server | Tls11Server | Tls12Server | UniServer) + } + + [StructLayout(LayoutKind.Sequential)] + internal struct Bindings + { + // see SecPkgContext_Bindings in + internal int BindingsLength; + internal IntPtr bindings; + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SecurityStatus.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SecurityStatus.cs new file mode 100644 index 0000000000..294fa1d863 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SecurityStatus.cs @@ -0,0 +1,54 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Server.WebListener +{ + internal enum SecurityStatus + { + // Success / Informational + OK = 0x00000000, + ContinueNeeded = unchecked((int)0x00090312), + CompleteNeeded = unchecked((int)0x00090313), + CompAndContinue = unchecked((int)0x00090314), + ContextExpired = unchecked((int)0x00090317), + CredentialsNeeded = unchecked((int)0x00090320), + Renegotiate = unchecked((int)0x00090321), + + // Errors + OutOfMemory = unchecked((int)0x80090300), + InvalidHandle = unchecked((int)0x80090301), + Unsupported = unchecked((int)0x80090302), + TargetUnknown = unchecked((int)0x80090303), + InternalError = unchecked((int)0x80090304), + PackageNotFound = unchecked((int)0x80090305), + NotOwner = unchecked((int)0x80090306), + CannotInstall = unchecked((int)0x80090307), + InvalidToken = unchecked((int)0x80090308), + CannotPack = unchecked((int)0x80090309), + QopNotSupported = unchecked((int)0x8009030A), + NoImpersonation = unchecked((int)0x8009030B), + LogonDenied = unchecked((int)0x8009030C), + UnknownCredentials = unchecked((int)0x8009030D), + NoCredentials = unchecked((int)0x8009030E), + MessageAltered = unchecked((int)0x8009030F), + OutOfSequence = unchecked((int)0x80090310), + NoAuthenticatingAuthority = unchecked((int)0x80090311), + IncompleteMessage = unchecked((int)0x80090318), + IncompleteCredentials = unchecked((int)0x80090320), + BufferNotEnough = unchecked((int)0x80090321), + WrongPrincipal = unchecked((int)0x80090322), + TimeSkew = unchecked((int)0x80090324), + UntrustedRoot = unchecked((int)0x80090325), + IllegalMessage = unchecked((int)0x80090326), + CertUnknown = unchecked((int)0x80090327), + CertExpired = unchecked((int)0x80090328), + AlgorithmMismatch = unchecked((int)0x80090331), + SecurityQosFailed = unchecked((int)0x80090332), + SmartcardLogonRequired = unchecked((int)0x8009033E), + UnsupportedPreauth = unchecked((int)0x80090343), + BadBinding = unchecked((int)0x80090346) + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs new file mode 100644 index 0000000000..9dfdb69ac3 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs @@ -0,0 +1,342 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Text; + +namespace Microsoft.AspNet.Server.WebListener +{ + // a little perf app measured these times when comparing the internal + // buffer implemented as a managed byte[] or unmanaged memory IntPtr + // that's why we use byte[] + // byte[] total ms:19656 + // IntPtr total ms:25671 + + /// + /// + /// This class is used when subclassing EndPoint, and provides indication + /// on how to format the memory buffers that winsock uses for network addresses. + /// + /// + internal class SocketAddress + { + private const int NumberOfIPv6Labels = 8; + // Lower case hex, no leading zeros + private const string IPv6NumberFormat = "{0:x}"; + private const string IPv6StringSeparator = ":"; + private const string IPv4StringFormat = "{0:d}.{1:d}.{2:d}.{3:d}"; + + internal const int IPv6AddressSize = 28; + internal const int IPv4AddressSize = 16; + + private const int WriteableOffset = 2; + + private int _size; + private byte[] _buffer; + private int _hash; + + /// + /// [To be supplied.] + /// + public SocketAddress(AddressFamily family, int size) + { + if (size < WriteableOffset) + { + // it doesn't make sense to create a socket address with less tha + // 2 bytes, that's where we store the address family. + + throw new ArgumentOutOfRangeException("size"); + } + _size = size; + _buffer = new byte[((size / IntPtr.Size) + 2) * IntPtr.Size]; // sizeof DWORD + +#if BIGENDIAN + m_Buffer[0] = unchecked((byte)((int)family>>8)); + m_Buffer[1] = unchecked((byte)((int)family )); +#else + _buffer[0] = unchecked((byte)((int)family)); + _buffer[1] = unchecked((byte)((int)family >> 8)); +#endif + } + + internal byte[] Buffer + { + get { return _buffer; } + } + + internal AddressFamily Family + { + get + { + int family; +#if BIGENDIAN + family = ((int)m_Buffer[0]<<8) | m_Buffer[1]; +#else + family = _buffer[0] | ((int)_buffer[1] << 8); +#endif + return (AddressFamily)family; + } + } + + internal int Size + { + get + { + return _size; + } + } + + // access to unmanaged serialized data. this doesn't + // allow access to the first 2 bytes of unmanaged memory + // that are supposed to contain the address family which + // is readonly. + // + // you can still use negative offsets as a back door in case + // winsock changes the way it uses SOCKADDR. maybe we want to prohibit it? + // maybe we should make the class sealed to avoid potentially dangerous calls + // into winsock with unproperly formatted data? + + /// + /// [To be supplied.] + /// + private byte this[int offset] + { + get + { + // access + if (offset < 0 || offset >= Size) + { + throw new ArgumentOutOfRangeException("offset"); + } + return _buffer[offset]; + } + } + + internal int GetPort() + { + return (int)((_buffer[2] << 8 & 0xFF00) | (_buffer[3])); + } + + public override bool Equals(object comparand) + { + SocketAddress castedComparand = comparand as SocketAddress; + if (castedComparand == null || this.Size != castedComparand.Size) + { + return false; + } + for (int i = 0; i < this.Size; i++) + { + if (this[i] != castedComparand[i]) + { + return false; + } + } + return true; + } + + public override int GetHashCode() + { + if (_hash == 0) + { + int i; + int size = Size & ~3; + + for (i = 0; i < size; i += 4) + { + _hash ^= (int)_buffer[i] + | ((int)_buffer[i + 1] << 8) + | ((int)_buffer[i + 2] << 16) + | ((int)_buffer[i + 3] << 24); + } + if ((Size & 3) != 0) + { + int remnant = 0; + int shift = 0; + + for (; i < Size; ++i) + { + remnant |= ((int)_buffer[i]) << shift; + shift += 8; + } + _hash ^= remnant; + } + } + return _hash; + } + + public override string ToString() + { + StringBuilder bytes = new StringBuilder(); + for (int i = WriteableOffset; i < this.Size; i++) + { + if (i > WriteableOffset) + { + bytes.Append(","); + } + bytes.Append(this[i].ToString(NumberFormatInfo.InvariantInfo)); + } + return Family.ToString() + ":" + Size.ToString(NumberFormatInfo.InvariantInfo) + ":{" + bytes.ToString() + "}"; + } + + internal string GetIPAddressString() + { + if (Family == AddressFamily.InterNetworkV6) + { + return GetIpv6AddressString(); + } + else if (Family == AddressFamily.InterNetwork) + { + return GetIPv4AddressString(); + } + else + { + return null; + } + } + + private string GetIPv4AddressString() + { + Contract.Assert(Size >= IPv4AddressSize); + + return string.Format(CultureInfo.InvariantCulture, IPv4StringFormat, + _buffer[4], _buffer[5], _buffer[6], _buffer[7]); + } + + // TODO: Does scope ID ever matter? + private unsafe string GetIpv6AddressString() + { + Contract.Assert(Size >= IPv6AddressSize); + + fixed (byte* rawBytes = _buffer) + { + // Convert from bytes to shorts. + ushort* rawShorts = stackalloc ushort[NumberOfIPv6Labels]; + int numbersOffset = 0; + // The address doesn't start at the beginning of the buffer. + for (int i = 8; i < ((NumberOfIPv6Labels * 2) + 8); i += 2) + { + rawShorts[numbersOffset++] = (ushort)(rawBytes[i] << 8 | rawBytes[i + 1]); + } + return GetIPv6AddressString(rawShorts); + } + } + + private static unsafe string GetIPv6AddressString(ushort* numbers) + { + // RFC 5952 Sections 4 & 5 - Compressed, lower case, with possible embedded IPv4 addresses. + + // Start to finish, inclusive. <-1, -1> for no compression + KeyValuePair range = FindCompressionRange(numbers); + bool ipv4Embedded = ShouldHaveIpv4Embedded(numbers); + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < NumberOfIPv6Labels; i++) + { + if (ipv4Embedded && i == (NumberOfIPv6Labels - 2)) + { + // Write the remaining digits as an IPv4 address + builder.Append(IPv6StringSeparator); + builder.Append(string.Format(CultureInfo.InvariantCulture, IPv4StringFormat, + numbers[i] >> 8, numbers[i] & 0xFF, numbers[i + 1] >> 8, numbers[i + 1] & 0xFF)); + break; + } + + // Compression; 1::1, ::1, 1:: + if (range.Key == i) + { + // Start compression, add : + builder.Append(IPv6StringSeparator); + } + if (range.Key <= i && range.Value == (NumberOfIPv6Labels - 1)) + { + // Remainder compressed; 1:: + builder.Append(IPv6StringSeparator); + break; + } + if (range.Key <= i && i <= range.Value) + { + continue; // Compressed + } + + if (i != 0) + { + builder.Append(IPv6StringSeparator); + } + builder.Append(string.Format(CultureInfo.InvariantCulture, IPv6NumberFormat, numbers[i])); + } + + return builder.ToString(); + } + + // RFC 5952 Section 4.2.3 + // Longest consecutive sequence of zero segments, minimum 2. + // On equal, first sequence wins. + // <-1, -1> for no compression. + private static unsafe KeyValuePair FindCompressionRange(ushort* numbers) + { + int longestSequenceLength = 0; + int longestSequenceStart = -1; + + int currentSequenceLength = 0; + for (int i = 0; i < NumberOfIPv6Labels; i++) + { + if (numbers[i] == 0) + { + // In a sequence + currentSequenceLength++; + if (currentSequenceLength > longestSequenceLength) + { + longestSequenceLength = currentSequenceLength; + longestSequenceStart = i - currentSequenceLength + 1; + } + } + else + { + currentSequenceLength = 0; + } + } + + if (longestSequenceLength >= 2) + { + return new KeyValuePair(longestSequenceStart, + longestSequenceStart + longestSequenceLength - 1); + } + + return new KeyValuePair(-1, -1); // No compression + } + + // Returns true if the IPv6 address should be formated with an embedded IPv4 address: + // ::192.168.1.1 + private static unsafe bool ShouldHaveIpv4Embedded(ushort* numbers) + { + // 0:0 : 0:0 : x:x : x.x.x.x + if (numbers[0] == 0 && numbers[1] == 0 && numbers[2] == 0 && numbers[3] == 0 && numbers[6] != 0) + { + // RFC 5952 Section 5 - 0:0 : 0:0 : 0:[0 | FFFF] : x.x.x.x + if (numbers[4] == 0 && (numbers[5] == 0 || numbers[5] == 0xFFFF)) + { + return true; + + // SIIT - 0:0 : 0:0 : FFFF:0 : x.x.x.x + } + else if (numbers[4] == 0xFFFF && numbers[5] == 0) + { + return true; + } + } + // ISATAP + if (numbers[4] == 0 && numbers[5] == 0x5EFE) + { + return true; + } + + return false; + } + } // class SocketAddress +} // namespace System.Net diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs new file mode 100644 index 0000000000..0eb890cf8b --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs @@ -0,0 +1,1129 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class UnsafeNclNativeMethods + { + private const string KERNEL32 = "kernel32.dll"; + private const string SECUR32 = "secur32.dll"; + private const string HTTPAPI = "httpapi.dll"; + + // CONSIDER: Make this an enum, requires changing a lot of types from uint to ErrorCodes. + internal static class ErrorCodes + { + internal const uint ERROR_SUCCESS = 0; + internal const uint ERROR_HANDLE_EOF = 38; + internal const uint ERROR_NOT_SUPPORTED = 50; + internal const uint ERROR_INVALID_PARAMETER = 87; + internal const uint ERROR_ALREADY_EXISTS = 183; + internal const uint ERROR_MORE_DATA = 234; + internal const uint ERROR_OPERATION_ABORTED = 995; + internal const uint ERROR_IO_PENDING = 997; + internal const uint ERROR_NOT_FOUND = 1168; + internal const uint ERROR_CONNECTION_INVALID = 1229; + } + + [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint GetCurrentThreadId(); + + [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static unsafe extern uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped); + + [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static unsafe extern bool SetFileCompletionNotificationModes(SafeHandle handle, FileCompletionNotificationModes modes); + + [Flags] + internal enum FileCompletionNotificationModes : byte + { + None = 0, + SkipCompletionPortOnSuccess = 1, + SkipSetEventOnHandle = 2 + } + + internal static class SafeNetHandles + { + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + internal static extern int FreeContextBuffer( + [In] IntPtr contextBuffer); + + [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] + internal static unsafe extern int QueryContextAttributesW( + ref SSPIHandle contextHandle, + [In] ContextAttribute attribute, + [In] void* buffer); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern unsafe uint HttpCreateRequestQueue(HttpApi.HTTPAPI_VERSION version, string pName, + Microsoft.AspNet.Server.WebListener.UnsafeNclNativeMethods.SECURITY_ATTRIBUTES pSecurityAttributes, uint flags, out HttpRequestQueueV2Handle pReqQueueHandle); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + internal static extern bool CloseHandle(IntPtr handle); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); + + [DllImport(KERNEL32, EntryPoint = "LocalAlloc", SetLastError = true)] + internal static extern SafeLocalFreeChannelBinding LocalAllocChannelBinding(int uFlags, UIntPtr sizetdwBytes); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr LocalFree(IntPtr handle); + + [DllImport(KERNEL32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); + } + + internal static unsafe class HttpApi + { + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpInitialize(HTTPAPI_VERSION version, uint flags, void* pReserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveRequestEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, IntPtr pEntityBuffer, uint entityBufferLength, out uint bytesReturned, SafeNativeOverlapped pOverlapped); + + [DllImport(HTTPAPI, EntryPoint = "HttpReceiveRequestEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveRequestEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, void* pEntityBuffer, uint entityBufferLength, out uint bytesReturned, [In] SafeHandle pOverlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, HTTP_SSL_CLIENT_CERT_INFO* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, byte* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped); + + [SuppressMessage("Microsoft.Interoperability", "CA1415:DeclarePInvokesCorrectly", Justification = "NativeOverlapped is now wrapped by SafeNativeOverlapped")] + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveHttpRequest(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_REQUEST* pRequestBuffer, uint requestBufferLength, uint* pBytesReturned, SafeNativeOverlapped pOverlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE* pHttpResponse, void* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK* pEntityChunks, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCancelHttpRequest(SafeHandle requestQueueHandle, ulong requestId, IntPtr pOverlapped); + + [DllImport(HTTPAPI, EntryPoint = "HttpSendResponseEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSendResponseEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, IntPtr pEntityChunks, out uint pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeHandle pOverlapped, IntPtr pLogData); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpWaitForDisconnect(SafeHandle requestQueueHandle, ulong connectionId, SafeNativeOverlapped pOverlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCreateServerSession(HTTPAPI_VERSION version, ulong* serverSessionId, uint reserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCreateUrlGroup(ulong serverSessionId, ulong* urlGroupId, uint reserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint HttpAddUrlToUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, ulong context, uint pReserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSetUrlGroupProperty(ulong urlGroupId, HTTP_SERVER_PROPERTY serverProperty, IntPtr pPropertyInfo, uint propertyInfoLength); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint HttpRemoveUrlFromUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, uint flags); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCloseServerSession(ulong serverSessionId); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCloseUrlGroup(ulong urlGroupId); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSetRequestQueueProperty(SafeHandle requestQueueHandle, HTTP_SERVER_PROPERTY serverProperty, IntPtr pPropertyInfo, uint propertyInfoLength, uint reserved, IntPtr pReserved); + + internal enum HTTP_API_VERSION + { + Invalid, + Version10, + Version20, + } + + // see http.w for definitions + internal enum HTTP_SERVER_PROPERTY + { + HttpServerAuthenticationProperty, + HttpServerLoggingProperty, + HttpServerQosProperty, + HttpServerTimeoutsProperty, + HttpServerQueueLengthProperty, + HttpServerStateProperty, + HttpServer503VerbosityProperty, + HttpServerBindingProperty, + HttpServerExtendedAuthenticationProperty, + HttpServerListenEndpointProperty, + HttpServerChannelBindProperty, + HttpServerProtectionLevelProperty, + } + + // Currently only one request info type is supported but the enum is for future extensibility. + + internal enum HTTP_REQUEST_INFO_TYPE + { + HttpRequestInfoTypeAuth, + } + + internal enum HTTP_RESPONSE_INFO_TYPE + { + HttpResponseInfoTypeMultipleKnownHeaders, + HttpResponseInfoTypeAuthenticationProperty, + HttpResponseInfoTypeQosProperty, + } + + internal enum HTTP_TIMEOUT_TYPE + { + EntityBody, + DrainEntityBody, + RequestQueue, + IdleConnection, + HeaderWait, + MinSendRate, + } + + internal const int MaxTimeout = 6; + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_VERSION + { + internal ushort MajorVersion; + internal ushort MinorVersion; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_KNOWN_HEADER + { + internal ushort RawValueLength; + internal sbyte* pRawValue; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct HTTP_DATA_CHUNK + { + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used natively")] + [FieldOffset(0)] + internal HTTP_DATA_CHUNK_TYPE DataChunkType; + + [FieldOffset(8)] + internal FromMemory fromMemory; + + [FieldOffset(8)] + internal FromFileHandle fromFile; + } + + [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable", + Justification = "This type does not own the native buffer")] + [StructLayout(LayoutKind.Sequential)] + internal struct FromMemory + { + // 4 bytes for 32bit, 8 bytes for 64bit + internal IntPtr pBuffer; + internal uint BufferLength; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct FromFileHandle + { + internal ulong offset; + internal ulong count; + internal IntPtr fileHandle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTPAPI_VERSION + { + internal ushort HttpApiMajorVersion; + internal ushort HttpApiMinorVersion; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_COOKED_URL + { + internal ushort FullUrlLength; + internal ushort HostLength; + internal ushort AbsPathLength; + internal ushort QueryStringLength; + internal ushort* pFullUrl; + internal ushort* pHost; + internal ushort* pAbsPath; + internal ushort* pQueryString; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SOCKADDR + { + internal ushort sa_family; + internal byte sa_data; + internal byte sa_data_02; + internal byte sa_data_03; + internal byte sa_data_04; + internal byte sa_data_05; + internal byte sa_data_06; + internal byte sa_data_07; + internal byte sa_data_08; + internal byte sa_data_09; + internal byte sa_data_10; + internal byte sa_data_11; + internal byte sa_data_12; + internal byte sa_data_13; + internal byte sa_data_14; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_TRANSPORT_ADDRESS + { + internal SOCKADDR* pRemoteAddress; + internal SOCKADDR* pLocalAddress; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SSL_CLIENT_CERT_INFO + { + internal uint CertFlags; + internal uint CertEncodedSize; + internal byte* pCertEncoded; + internal void* Token; + internal byte CertDeniedByMapper; + } + + internal enum HTTP_SERVICE_BINDING_TYPE : uint + { + HttpServiceBindingTypeNone = 0, + HttpServiceBindingTypeW, + HttpServiceBindingTypeA + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVICE_BINDING_BASE + { + internal HTTP_SERVICE_BINDING_TYPE Type; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_CHANNEL_BIND_STATUS + { + internal IntPtr ServiceName; + internal IntPtr ChannelToken; + internal uint ChannelTokenSize; + internal uint Flags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_UNKNOWN_HEADER + { + internal ushort NameLength; + internal ushort RawValueLength; + internal sbyte* pName; + internal sbyte* pRawValue; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SSL_INFO + { + internal ushort ServerCertKeySize; + internal ushort ConnectionKeySize; + internal uint ServerCertIssuerSize; + internal uint ServerCertSubjectSize; + internal sbyte* pServerCertIssuer; + internal sbyte* pServerCertSubject; + internal HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo; + internal uint SslClientCertNegotiated; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_HEADERS + { + internal ushort UnknownHeaderCount; + internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; + internal ushort TrailerCount; + internal HTTP_UNKNOWN_HEADER* pTrailers; + internal HTTP_KNOWN_HEADER KnownHeaders; + internal HTTP_KNOWN_HEADER KnownHeaders_02; + internal HTTP_KNOWN_HEADER KnownHeaders_03; + internal HTTP_KNOWN_HEADER KnownHeaders_04; + internal HTTP_KNOWN_HEADER KnownHeaders_05; + internal HTTP_KNOWN_HEADER KnownHeaders_06; + internal HTTP_KNOWN_HEADER KnownHeaders_07; + internal HTTP_KNOWN_HEADER KnownHeaders_08; + internal HTTP_KNOWN_HEADER KnownHeaders_09; + internal HTTP_KNOWN_HEADER KnownHeaders_10; + internal HTTP_KNOWN_HEADER KnownHeaders_11; + internal HTTP_KNOWN_HEADER KnownHeaders_12; + internal HTTP_KNOWN_HEADER KnownHeaders_13; + internal HTTP_KNOWN_HEADER KnownHeaders_14; + internal HTTP_KNOWN_HEADER KnownHeaders_15; + internal HTTP_KNOWN_HEADER KnownHeaders_16; + internal HTTP_KNOWN_HEADER KnownHeaders_17; + internal HTTP_KNOWN_HEADER KnownHeaders_18; + internal HTTP_KNOWN_HEADER KnownHeaders_19; + internal HTTP_KNOWN_HEADER KnownHeaders_20; + internal HTTP_KNOWN_HEADER KnownHeaders_21; + internal HTTP_KNOWN_HEADER KnownHeaders_22; + internal HTTP_KNOWN_HEADER KnownHeaders_23; + internal HTTP_KNOWN_HEADER KnownHeaders_24; + internal HTTP_KNOWN_HEADER KnownHeaders_25; + internal HTTP_KNOWN_HEADER KnownHeaders_26; + internal HTTP_KNOWN_HEADER KnownHeaders_27; + internal HTTP_KNOWN_HEADER KnownHeaders_28; + internal HTTP_KNOWN_HEADER KnownHeaders_29; + internal HTTP_KNOWN_HEADER KnownHeaders_30; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_HEADERS + { + internal ushort UnknownHeaderCount; + internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; + internal ushort TrailerCount; + internal HTTP_UNKNOWN_HEADER* pTrailers; + internal HTTP_KNOWN_HEADER KnownHeaders; + internal HTTP_KNOWN_HEADER KnownHeaders_02; + internal HTTP_KNOWN_HEADER KnownHeaders_03; + internal HTTP_KNOWN_HEADER KnownHeaders_04; + internal HTTP_KNOWN_HEADER KnownHeaders_05; + internal HTTP_KNOWN_HEADER KnownHeaders_06; + internal HTTP_KNOWN_HEADER KnownHeaders_07; + internal HTTP_KNOWN_HEADER KnownHeaders_08; + internal HTTP_KNOWN_HEADER KnownHeaders_09; + internal HTTP_KNOWN_HEADER KnownHeaders_10; + internal HTTP_KNOWN_HEADER KnownHeaders_11; + internal HTTP_KNOWN_HEADER KnownHeaders_12; + internal HTTP_KNOWN_HEADER KnownHeaders_13; + internal HTTP_KNOWN_HEADER KnownHeaders_14; + internal HTTP_KNOWN_HEADER KnownHeaders_15; + internal HTTP_KNOWN_HEADER KnownHeaders_16; + internal HTTP_KNOWN_HEADER KnownHeaders_17; + internal HTTP_KNOWN_HEADER KnownHeaders_18; + internal HTTP_KNOWN_HEADER KnownHeaders_19; + internal HTTP_KNOWN_HEADER KnownHeaders_20; + internal HTTP_KNOWN_HEADER KnownHeaders_21; + internal HTTP_KNOWN_HEADER KnownHeaders_22; + internal HTTP_KNOWN_HEADER KnownHeaders_23; + internal HTTP_KNOWN_HEADER KnownHeaders_24; + internal HTTP_KNOWN_HEADER KnownHeaders_25; + internal HTTP_KNOWN_HEADER KnownHeaders_26; + internal HTTP_KNOWN_HEADER KnownHeaders_27; + internal HTTP_KNOWN_HEADER KnownHeaders_28; + internal HTTP_KNOWN_HEADER KnownHeaders_29; + internal HTTP_KNOWN_HEADER KnownHeaders_30; + internal HTTP_KNOWN_HEADER KnownHeaders_31; + internal HTTP_KNOWN_HEADER KnownHeaders_32; + internal HTTP_KNOWN_HEADER KnownHeaders_33; + internal HTTP_KNOWN_HEADER KnownHeaders_34; + internal HTTP_KNOWN_HEADER KnownHeaders_35; + internal HTTP_KNOWN_HEADER KnownHeaders_36; + internal HTTP_KNOWN_HEADER KnownHeaders_37; + internal HTTP_KNOWN_HEADER KnownHeaders_38; + internal HTTP_KNOWN_HEADER KnownHeaders_39; + internal HTTP_KNOWN_HEADER KnownHeaders_40; + internal HTTP_KNOWN_HEADER KnownHeaders_41; + } + + internal enum HTTP_VERB : int + { + HttpVerbUnparsed = 0, + HttpVerbUnknown = 1, + HttpVerbInvalid = 2, + HttpVerbOPTIONS = 3, + HttpVerbGET = 4, + HttpVerbHEAD = 5, + HttpVerbPOST = 6, + HttpVerbPUT = 7, + HttpVerbDELETE = 8, + HttpVerbTRACE = 9, + HttpVerbCONNECT = 10, + HttpVerbTRACK = 11, + HttpVerbMOVE = 12, + HttpVerbCOPY = 13, + HttpVerbPROPFIND = 14, + HttpVerbPROPPATCH = 15, + HttpVerbMKCOL = 16, + HttpVerbLOCK = 17, + HttpVerbUNLOCK = 18, + HttpVerbSEARCH = 19, + HttpVerbMaximum = 20, + } + + internal static readonly string[] HttpVerbs = new string[] + { + null, + "Unknown", + "Invalid", + "OPTIONS", + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "TRACE", + "CONNECT", + "TRACK", + "MOVE", + "COPY", + "PROPFIND", + "PROPPATCH", + "MKCOL", + "LOCK", + "UNLOCK", + "SEARCH", + }; + + internal enum HTTP_DATA_CHUNK_TYPE : int + { + HttpDataChunkFromMemory = 0, + HttpDataChunkFromFileHandle = 1, + HttpDataChunkFromFragmentCache = 2, + HttpDataChunkMaximum = 3, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_INFO + { + internal HTTP_RESPONSE_INFO_TYPE Type; + internal uint Length; + internal void* pInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE + { + internal uint Flags; + internal HTTP_VERSION Version; + internal ushort StatusCode; + internal ushort ReasonLength; + internal sbyte* pReason; + internal HTTP_RESPONSE_HEADERS Headers; + internal ushort EntityChunkCount; + internal HTTP_DATA_CHUNK* pEntityChunks; + internal ushort ResponseInfoCount; + internal HTTP_RESPONSE_INFO* pResponseInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_AUTH_INFO + { + internal HTTP_AUTH_STATUS AuthStatus; + internal uint SecStatus; + internal uint Flags; + internal HTTP_REQUEST_AUTH_TYPE AuthType; + internal IntPtr AccessToken; + internal uint ContextAttributes; + internal uint PackedContextLength; + internal uint PackedContextType; + internal IntPtr PackedContext; + internal uint MutualAuthDataLength; + internal char* pMutualAuthData; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_INFO + { + internal HTTP_REQUEST_INFO_TYPE InfoType; + internal uint InfoLength; + internal HTTP_REQUEST_AUTH_INFO* pInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST + { + internal uint Flags; + internal ulong ConnectionId; + internal ulong RequestId; + internal ulong UrlContext; + internal HTTP_VERSION Version; + internal HTTP_VERB Verb; + internal ushort UnknownVerbLength; + internal ushort RawUrlLength; + internal sbyte* pUnknownVerb; + internal sbyte* pRawUrl; + internal HTTP_COOKED_URL CookedUrl; + internal HTTP_TRANSPORT_ADDRESS Address; + internal HTTP_REQUEST_HEADERS Headers; + internal ulong BytesReceived; + internal ushort EntityChunkCount; + internal HTTP_DATA_CHUNK* pEntityChunks; + internal ulong RawConnectionId; + internal HTTP_SSL_INFO* pSslInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_V2 + { + internal HTTP_REQUEST Request; + internal ushort RequestInfoCount; + internal HTTP_REQUEST_INFO* pRequestInfo; + } + + internal enum HTTP_AUTH_STATUS + { + HttpAuthStatusSuccess, + HttpAuthStatusNotAuthenticated, + HttpAuthStatusFailure, + } + + internal enum HTTP_REQUEST_AUTH_TYPE + { + HttpRequestAuthTypeNone = 0, + HttpRequestAuthTypeBasic, + HttpRequestAuthTypeDigest, + HttpRequestAuthTypeNTLM, + HttpRequestAuthTypeNegotiate, + HttpRequestAuthTypeKerberos + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_INFO + { + internal HTTP_FLAGS Flags; + internal HTTP_AUTH_TYPES AuthSchemes; + internal bool ReceiveMutualAuth; + internal bool ReceiveContextHandle; + internal bool DisableNTLMCredentialCaching; + internal ulong ExFlags; + HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS DigestParams; + HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS BasicParams; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS + { + internal ushort DomainNameLength; + internal char* DomainName; + internal ushort RealmLength; + internal char* Realm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS + { + ushort RealmLength; + char* Realm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_TIMEOUT_LIMIT_INFO + { + internal HTTP_FLAGS Flags; + internal ushort EntityBody; + internal ushort DrainEntityBody; + internal ushort RequestQueue; + internal ushort IdleConnection; + internal ushort HeaderWait; + internal uint MinSendRate; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_BINDING_INFO + { + internal HTTP_FLAGS Flags; + internal IntPtr RequestQueueHandle; + } + + // see http.w for definitions + [Flags] + internal enum HTTP_FLAGS : uint + { + NONE = 0x00000000, + HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY = 0x00000001, + HTTP_RECEIVE_SECURE_CHANNEL_TOKEN = 0x00000001, + HTTP_SEND_RESPONSE_FLAG_DISCONNECT = 0x00000001, + HTTP_SEND_RESPONSE_FLAG_MORE_DATA = 0x00000002, + HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA = 0x00000004, + HTTP_SEND_RESPONSE_FLAG_RAW_HEADER = 0x00000004, + HTTP_SEND_REQUEST_FLAG_MORE_DATA = 0x00000001, + HTTP_PROPERTY_FLAG_PRESENT = 0x00000001, + HTTP_INITIALIZE_SERVER = 0x00000001, + HTTP_INITIALIZE_CBT = 0x00000004, + HTTP_SEND_RESPONSE_FLAG_OPAQUE = 0x00000040, + } + + [Flags] + internal enum HTTP_AUTH_TYPES : uint + { + NONE = 0x00000000, + HTTP_AUTH_ENABLE_BASIC = 0x00000001, + HTTP_AUTH_ENABLE_DIGEST = 0x00000002, + HTTP_AUTH_ENABLE_NTLM = 0x00000004, + HTTP_AUTH_ENABLE_NEGOTIATE = 0x00000008, + HTTP_AUTH_ENABLE_KERBEROS = 0x00000010, + } + + private const int HttpHeaderRequestMaximum = (int)HttpSysRequestHeader.UserAgent + 1; + private const int HttpHeaderResponseMaximum = (int)HttpSysResponseHeader.WwwAuthenticate + 1; + + internal static class HTTP_REQUEST_HEADER_ID + { + internal static string ToString(int position) + { + return _strings[position]; + } + + private static string[] _strings = + { + "Cache-Control", + "Connection", + "Date", + "Keep-Alive", + "Pragma", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Via", + "Warning", + + "Allow", + "Content-Length", + "Content-Type", + "Content-Encoding", + "Content-Language", + "Content-Location", + "Content-MD5", + "Content-Range", + "Expires", + "Last-Modified", + + "Accept", + "Accept-Charset", + "Accept-Encoding", + "Accept-Language", + "Authorization", + "Cookie", + "Expect", + "From", + "Host", + "If-Match", + + "If-Modified-Since", + "If-None-Match", + "If-Range", + "If-Unmodified-Since", + "Max-Forwards", + "Proxy-Authorization", + "Referer", + "Range", + "Te", + "Translate", + "User-Agent", + }; + } + + internal static class HTTP_RESPONSE_HEADER_ID + { + private static string[] _strings = + { + "Cache-Control", + "Connection", + "Date", + "Keep-Alive", + "Pragma", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Via", + "Warning", + + "Allow", + "Content-Length", + "Content-Type", + "Content-Encoding", + "Content-Language", + "Content-Location", + "Content-MD5", + "Content-Range", + "Expires", + "Last-Modified", + + "Accept-Ranges", + "Age", + "ETag", + "Location", + "Proxy-Authenticate", + "Retry-After", + "Server", + "Set-Cookie", + "Vary", + "WWW-Authenticate", + }; + + private static Dictionary _lookupTable = CreateLookupTable(); + + private static Dictionary CreateLookupTable() + { + Dictionary lookupTable = new Dictionary((int)Enum.HttpHeaderResponseMaximum, StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++) + { + lookupTable.Add(_strings[i], i); + } + return lookupTable; + } + + internal static int IndexOfKnownHeader(string HeaderName) + { + int index; + return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1; + } + + internal static string ToString(int position) + { + return _strings[position]; + } + + internal enum Enum + { + HttpHeaderCacheControl = 0, // general-header [section 4.5] + HttpHeaderConnection = 1, // general-header [section 4.5] + HttpHeaderDate = 2, // general-header [section 4.5] + HttpHeaderKeepAlive = 3, // general-header [not in rfc] + HttpHeaderPragma = 4, // general-header [section 4.5] + HttpHeaderTrailer = 5, // general-header [section 4.5] + HttpHeaderTransferEncoding = 6, // general-header [section 4.5] + HttpHeaderUpgrade = 7, // general-header [section 4.5] + HttpHeaderVia = 8, // general-header [section 4.5] + HttpHeaderWarning = 9, // general-header [section 4.5] + + HttpHeaderAllow = 10, // entity-header [section 7.1] + HttpHeaderContentLength = 11, // entity-header [section 7.1] + HttpHeaderContentType = 12, // entity-header [section 7.1] + HttpHeaderContentEncoding = 13, // entity-header [section 7.1] + HttpHeaderContentLanguage = 14, // entity-header [section 7.1] + HttpHeaderContentLocation = 15, // entity-header [section 7.1] + HttpHeaderContentMd5 = 16, // entity-header [section 7.1] + HttpHeaderContentRange = 17, // entity-header [section 7.1] + HttpHeaderExpires = 18, // entity-header [section 7.1] + HttpHeaderLastModified = 19, // entity-header [section 7.1] + + // Response Headers + + HttpHeaderAcceptRanges = 20, // response-header [section 6.2] + HttpHeaderAge = 21, // response-header [section 6.2] + HttpHeaderEtag = 22, // response-header [section 6.2] + HttpHeaderLocation = 23, // response-header [section 6.2] + HttpHeaderProxyAuthenticate = 24, // response-header [section 6.2] + HttpHeaderRetryAfter = 25, // response-header [section 6.2] + HttpHeaderServer = 26, // response-header [section 6.2] + HttpHeaderSetCookie = 27, // response-header [not in rfc] + HttpHeaderVary = 28, // response-header [section 6.2] + HttpHeaderWwwAuthenticate = 29, // response-header [section 6.2] + + HttpHeaderResponseMaximum = 30, + + HttpHeaderMaximum = 41 + } + } + + private static HTTPAPI_VERSION version; + + // This property is used by HttpListener to pass the version structure to the native layer in API + // calls. + + internal static HTTPAPI_VERSION Version + { + get + { + return version; + } + } + + // This property is used by HttpListener to get the Api version in use so that it uses appropriate + // Http APIs. + + internal static HTTP_API_VERSION ApiVersion + { + get + { + if (version.HttpApiMajorVersion == 2 && version.HttpApiMinorVersion == 0) + { + return HTTP_API_VERSION.Version20; + } + else if (version.HttpApiMajorVersion == 1 && version.HttpApiMinorVersion == 0) + { + return HTTP_API_VERSION.Version10; + } + else + { + return HTTP_API_VERSION.Invalid; + } + } + } + + static HttpApi() + { + InitHttpApi(2, 0); + } + + private static void InitHttpApi(ushort majorVersion, ushort minorVersion) + { + version.HttpApiMajorVersion = majorVersion; + version.HttpApiMinorVersion = minorVersion; + + // For pre-Win7 OS versions, we need to check whether http.sys contains the CBT patch. + // We do so by passing HTTP_INITIALIZE_CBT flag to HttpInitialize. If the flag is not + // supported, http.sys is not patched. Note that http.sys will return invalid parameter + // also on Win7, even though it shipped with CBT support. Therefore we must not pass + // the flag on Win7 and later. + uint statusCode = ErrorCodes.ERROR_SUCCESS; + + // on Win7 and later, we don't pass the CBT flag. CBT is always supported. + statusCode = HttpApi.HttpInitialize(version, (uint)HTTP_FLAGS.HTTP_INITIALIZE_SERVER, null); + + supported = statusCode == ErrorCodes.ERROR_SUCCESS; + } + + private static volatile bool supported; + internal static bool Supported + { + get + { + return supported; + } + } + + // Server API + + internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob, IntPtr originalAddress) + { + // Return value. + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + long fixup = pMemoryBlob - (byte*)originalAddress; + int index; + + // unknown headers + if (request->Headers.UnknownHeaderCount != 0) + { + HTTP_UNKNOWN_HEADER* pUnknownHeader = (HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders); + for (index = 0; index < request->Headers.UnknownHeaderCount; index++) + { + // For unknown headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will be null. + if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) + { + string headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength); + string headerValue; + if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) + { + headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength); + } + else + { + headerValue = string.Empty; + } + // Note that Http.Sys currently collapses all headers of the same name to a single string, so + // append will just set. + unknownHeaders.Append(headerName, headerValue); + } + pUnknownHeader++; + } + } + } + } + + private static string GetKnownHeader(HTTP_REQUEST* request, long fixup, int headerIndex) + { + string header = null; + + HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; + // For known headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will point to empty string ("\0") + if (pKnownHeader->pRawValue != null) + { + header = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength); + } + + return header; + } + + internal static string GetKnownHeader(byte[] memoryBlob, IntPtr originalAddress, int headerIndex) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + return GetKnownHeader((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress, headerIndex); + } + } + + private static unsafe string GetVerb(HTTP_REQUEST* request, long fixup) + { + string verb = null; + + if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnknown && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) + { + verb = HttpVerbs[(int)request->Verb]; + } + else if (request->Verb == HTTP_VERB.HttpVerbUnknown && request->pUnknownVerb != null) + { + verb = HeaderEncoding.GetString(request->pUnknownVerb + fixup, request->UnknownVerbLength); + } + + return verb; + } + + internal static unsafe string GetVerb(byte[] memoryBlob, IntPtr originalAddress) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + return GetVerb((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress); + } + } + + internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress) + { + // Return value. + HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown; + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) + { + verb = request->Verb; + } + } + + return verb; + } + + internal static uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) + { + // Return value. + uint dataRead = 0; + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + long fixup = pMemoryBlob - (byte*)originalAddress; + + if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) + { + HTTP_DATA_CHUNK* pDataChunk = (HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); + + fixed (byte* pReadBuffer = buffer) + { + byte* pTo = &pReadBuffer[offset]; + + while (dataChunkIndex < request->EntityChunkCount && dataRead < size) + { + if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength) + { + dataChunkOffset = 0; + dataChunkIndex++; + pDataChunk++; + } + else + { + byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup; + + uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset; + if (bytesToRead > (uint)size) + { + bytesToRead = (uint)size; + } + for (uint i = 0; i < bytesToRead; i++) + { + *(pTo++) = *(pFrom++); + } + dataRead += bytesToRead; + dataChunkOffset += bytesToRead; + } + } + } + } + // we're finished. + if (dataChunkIndex == request->EntityChunkCount) + { + dataChunkIndex = -1; + } + } + + return dataRead; + } + + internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, IntPtr originalAddress) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pRemoteAddress); + } + } + + internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, IntPtr originalAddress) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pLocalAddress); + } + } + + internal static SocketAddress GetEndPoint(byte[] memoryBlob, IntPtr originalAddress, byte* source) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + IntPtr address = source != null ? + (IntPtr)(pMemoryBlob - (byte*)originalAddress + source) : IntPtr.Zero; + return CopyOutAddress(address); + } + } + + private static SocketAddress CopyOutAddress(IntPtr address) + { + if (address != IntPtr.Zero) + { + ushort addressFamily = *((ushort*)address); + if (addressFamily == (ushort)AddressFamily.InterNetwork) + { + SocketAddress v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize); + fixed (byte* pBuffer = v4address.Buffer) + { + for (int index = 2; index < SocketAddress.IPv4AddressSize; index++) + { + pBuffer[index] = ((byte*)address)[index]; + } + } + return v4address; + } + if (addressFamily == (ushort)AddressFamily.InterNetworkV6) + { + SocketAddress v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize); + fixed (byte* pBuffer = v6address.Buffer) + { + for (int index = 2; index < SocketAddress.IPv6AddressSize; index++) + { + pBuffer[index] = ((byte*)address)[index]; + } + } + return v6address; + } + } + + return null; + } + } + + // DACL related stuff + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated natively")] + [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", + Justification = "Does not own the resource.")] + [StructLayout(LayoutKind.Sequential)] + internal class SECURITY_ATTRIBUTES + { + public int nLength = 12; + public SafeLocalMemHandle lpSecurityDescriptor = new SafeLocalMemHandle(IntPtr.Zero, false); + public bool bInheritHandle = false; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs new file mode 100644 index 0000000000..6b0b205db7 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs @@ -0,0 +1,108 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- +// Copyright 2011-2012 Katana contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + using AppFunc = Func, Task>; + using LoggerFactoryFunc = Func, bool>>; + + /// + /// Implements the Katana setup pattern for this server. + /// + public static class OwinServerFactory + { + /// + /// Populates the server capabilities. + /// Also included is a configurable instance of the server. + /// + /// + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] + public static void Initialize(IDictionary properties) + { + if (properties == null) + { + throw new ArgumentNullException("properties"); + } + + properties[Constants.VersionKey] = Constants.OwinVersion; + + IDictionary capabilities = + properties.Get>(Constants.ServerCapabilitiesKey) + ?? new Dictionary(); + properties[Constants.ServerCapabilitiesKey] = capabilities; + + // SendFile + capabilities[Constants.SendFileVersionKey] = Constants.SendFileVersion; + IDictionary sendfileSupport = new Dictionary(); + sendfileSupport[Constants.SendFileConcurrencyKey] = Constants.Overlapped; + capabilities[Constants.SendFileSupportKey] = sendfileSupport; + + // Opaque + if (ComNetOS.IsWin8orLater) + { + capabilities[Constants.OpaqueVersionKey] = Constants.OpaqueVersion; + } + + // Directly expose the server for advanced configuration. + properties[typeof(OwinWebListener).FullName] = new OwinWebListener(); + } + + /// + /// Creates a server and starts listening on the given addresses. + /// + /// The application entry point. + /// The configuration. + /// The server. Invoke Dispose to shut down. + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] + public static IDisposable Create(AppFunc app, IDictionary properties) + { + if (app == null) + { + throw new ArgumentNullException("app"); + } + if (properties == null) + { + throw new ArgumentNullException("properties"); + } + + var addresses = properties.Get>>("host.Addresses") + ?? new List>(); + + OwinWebListener server = properties.Get(typeof(OwinWebListener).FullName) + ?? new OwinWebListener(); + + var capabilities = + properties.Get>(Constants.ServerCapabilitiesKey) + ?? new Dictionary(); + + var loggerFactory = properties.Get(Constants.ServerLoggerFactoryKey); + + server.Start(app, addresses, capabilities, loggerFactory); + return server; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs new file mode 100644 index 0000000000..d6c1cd916a --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -0,0 +1,1107 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Security.Authentication.ExtendedProtection; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + using AppFunc = Func, Task>; + using LoggerFactoryFunc = Func, bool>>; + using LoggerFunc = Func, bool>; + + /// + /// An HTTP server wrapping the Http.Sys APIs that accepts requests and passes them on to the given OWIN application. + /// + public sealed class OwinWebListener : IDisposable + { + private const long DefaultRequestQueueLength = 1000; // Http.sys default. +#if NET45 + private static readonly Type ChannelBindingStatusType = typeof(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS); + private static readonly int RequestChannelBindStatusSize = + Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS)); + private static readonly int BindingInfoSize = + Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO)); +#else + private static readonly int RequestChannelBindStatusSize = + Marshal.SizeOf(); + private static readonly int BindingInfoSize = + Marshal.SizeOf(); +#endif + private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; + private static readonly int DefaultMaxRequests = Int32.MaxValue; + + // Win8# 559317 fixed a bug in Http.sys's HttpReceiveClientCertificate method. + // Without this fix IOCP callbacks were not being called although ERROR_IO_PENDING was + // returned from HttpReceiveClientCertificate when using the + // FileCompletionNotificationModes.SkipCompletionPortOnSuccess flag. + // This bug was only hit when the buffer passed into HttpReceiveClientCertificate + // (1500 bytes initially) is tool small for the certificate. + // Due to this bug in downlevel operating systems the FileCompletionNotificationModes.SkipCompletionPortOnSuccess + // flag is only used on Win8 and later. + internal static readonly bool SkipIOCPCallbackOnSuccess = ComNetOS.IsWin8orLater; + + // Mitigate potential DOS attacks by limiting the number of unknown headers we accept. Numerous header names + // with hash collisions will cause the server to consume excess CPU. 1000 headers limits CPU time to under + // 0.5 seconds per request. Respond with a 400 Bad Request. + private const int UnknownHeaderLimit = 1000; + + private readonly ConcurrentDictionary _connectionCancellationTokens; + + private AppFunc _appFunc; + private IDictionary _capabilities; + private LoggerFunc _logger; + + private SafeHandle _requestQueueHandle; + private volatile State _state; // m_State is set only within lock blocks, but often read outside locks. + private bool _ignoreWriteExceptions; + private HttpServerSessionHandle _serverSessionHandle; + private ulong _urlGroupId; + private TimeoutManager _timeoutManager; + private AuthenticationManager _authManager; + private bool _v2Initialized; + + private object _internalLock; + + private List _uriPrefixes = new List(); + + private PumpLimits _pumpLimits; + private int _currentOutstandingAccepts; + private int _currentOutstandingRequests; + private Action _offloadListenForNextRequest; + + // The native request queue + private long? _requestQueueLength; + + internal OwinWebListener() + { + if (!UnsafeNclNativeMethods.HttpApi.Supported) + { + throw new PlatformNotSupportedException(); + } + + Debug.Assert(UnsafeNclNativeMethods.HttpApi.ApiVersion == + UnsafeNclNativeMethods.HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version"); + + _state = State.Stopped; + _internalLock = new object(); + + _timeoutManager = new TimeoutManager(this); + _authManager = new AuthenticationManager(this); + _connectionCancellationTokens = new ConcurrentDictionary(); + + _offloadListenForNextRequest = new Action(ListenForNextRequestAsync); + + _pumpLimits = new PumpLimits(DefaultMaxAccepts, DefaultMaxRequests); + } + + internal enum State + { + Stopped, + Started, + Disposed, + } + + internal LoggerFunc Logger + { + get { return _logger; } + } + + internal List UriPrefixes + { + get { return _uriPrefixes; } + } + + internal IDictionary Capabilities + { + get { return _capabilities; } + } + + internal SafeHandle RequestQueueHandle + { + get + { + return _requestQueueHandle; + } + } + + /// + /// Exposes the Http.Sys timeout configurations. These may also be configured in the registry. + /// + public TimeoutManager TimeoutManager + { + get + { + ValidateV2Property(); + Debug.Assert(_timeoutManager != null, "Timeout manager is not assigned"); + return _timeoutManager; + } + } + + public AuthenticationManager AuthenticationManager + { + get + { + ValidateV2Property(); + Debug.Assert(_authManager != null, "Auth manager is not assigned"); + return _authManager; + } + } + + internal static bool IsSupported + { + get + { + return UnsafeNclNativeMethods.HttpApi.Supported; + } + } + + internal bool IsListening + { + get + { + return _state == State.Started; + } + } + + internal bool IgnoreWriteExceptions + { + get + { + return _ignoreWriteExceptions; + } + set + { + CheckDisposed(); + _ignoreWriteExceptions = value; + } + } + + private bool CanAcceptMoreRequests + { + get + { + PumpLimits limits = _pumpLimits; + return (_currentOutstandingAccepts < limits.MaxOutstandingAccepts + && _currentOutstandingRequests < limits.MaxOutstandingRequests - _currentOutstandingAccepts); + } + } + + /// + /// These are merged as one operation because they should be swapped out atomically. + /// This controls how many requests the server attempts to process concurrently. + /// + /// The maximum number of pending accepts. + /// The maximum number of outstanding requests. + public void SetRequestProcessingLimits(int maxAccepts, int maxRequests) + { + _pumpLimits = new PumpLimits(maxAccepts, maxRequests); + + // Kick the pump in case we went from zero to non-zero limits. + OffloadListenForNextRequestAsync(); + } + + /// + /// Gets the request processing limits. + /// + /// The maximum number of pending accepts. + /// The maximum number of outstanding requests. + [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "By design")] + [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "By design")] + public void GetRequestProcessingLimits(out int maxAccepts, out int maxRequests) + { + PumpLimits limits = _pumpLimits; + maxAccepts = limits.MaxOutstandingAccepts; + maxRequests = limits.MaxOutstandingRequests; + } + + /// + /// Sets the maximum number of requests that will be queued up in Http.Sys. + /// + /// + public void SetRequestQueueLimit(long limit) + { + if (limit <= 0) + { + throw new ArgumentOutOfRangeException("limit", limit, string.Empty); + } + if ((!_requestQueueLength.HasValue && limit == DefaultRequestQueueLength) + || (_requestQueueLength.HasValue && limit == _requestQueueLength.Value)) + { + return; + } + + _requestQueueLength = limit; + + SetRequestQueueLimit(); + } + + private unsafe void SetRequestQueueLimit() + { + // The listener must be active for this to work. Call from Start after activating. + if (!IsListening || !_requestQueueLength.HasValue) + { + return; + } + + long length = _requestQueueLength.Value; + uint result = UnsafeNclNativeMethods.HttpApi.HttpSetRequestQueueProperty(_requestQueueHandle, + UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, + new IntPtr((void*)&length), (uint)Marshal.SizeOf(length), 0, IntPtr.Zero); + + if (result != 0) + { + throw new WebListenerException((int)result); + } + } + + private void ValidateV2Property() + { + // Make sure that calling CheckDisposed and SetupV2Config is an atomic operation. This + // avoids race conditions if the listener is aborted/closed after CheckDisposed(), but + // before SetupV2Config(). + lock (_internalLock) + { + CheckDisposed(); + SetupV2Config(); + } + } + + internal void SetUrlGroupProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize) + { + ValidateV2Property(); + uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; + + Debug.Assert(_urlGroupId != 0, "SetUrlGroupProperty called with invalid url group id"); + Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); + + // Set the url group property using Http Api. + + statusCode = UnsafeNclNativeMethods.HttpApi.HttpSetUrlGroupProperty( + _urlGroupId, property, info, infosize); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + WebListenerException exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_logger, "SetUrlGroupProperty", exception); + throw exception; + } + } + + internal void RemoveAll(bool clear) + { + CheckDisposed(); + // go through the uri list and unregister for each one of them + if (_uriPrefixes.Count > 0) + { + LogHelper.LogInfo(_logger, "RemoveAll"); + if (_state == State.Started) + { + foreach (Prefix registeredPrefix in _uriPrefixes) + { + // ignore possible failures + InternalRemovePrefix(registeredPrefix.Whole); + } + } + + if (clear) + { + _uriPrefixes.Clear(); + } + } + } + + private IntPtr DangerousGetHandle() + { + return _requestQueueHandle.DangerousGetHandle(); + } + + private unsafe void SetupV2Config() + { + uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; + ulong id = 0; + + // If we have already initialized V2 config, then nothing to do. + + if (_v2Initialized) + { + return; + } + + // V2 initialization sequence: + // 1. Create server session + // 2. Create url group + // 3. Create request queue - Done in Start() + // 4. Add urls to url group - Done in Start() + // 5. Attach request queue to url group - Done in Start() + + try + { + statusCode = UnsafeNclNativeMethods.HttpApi.HttpCreateServerSession( + UnsafeNclNativeMethods.HttpApi.Version, &id, 0); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new WebListenerException((int)statusCode); + } + + Debug.Assert(id != 0, "Invalid id returned by HttpCreateServerSession"); + + _serverSessionHandle = new HttpServerSessionHandle(id); + + id = 0; + statusCode = UnsafeNclNativeMethods.HttpApi.HttpCreateUrlGroup( + _serverSessionHandle.DangerousGetServerSessionId(), &id, 0); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new WebListenerException((int)statusCode); + } + + Debug.Assert(id != 0, "Invalid id returned by HttpCreateUrlGroup"); + _urlGroupId = id; + + _v2Initialized = true; + } + catch (Exception exception) + { + // If V2 initialization fails, we mark object as unusable. + _state = State.Disposed; + // If Url group or request queue creation failed, close server session before throwing. + if (_serverSessionHandle != null) + { + _serverSessionHandle.Dispose(); + } + LogHelper.LogException(_logger, "SetupV2Config", exception); + throw; + } + } + + internal void Start(AppFunc app, IList> addresses, IDictionary capabilities, LoggerFactoryFunc loggerFactory) + { + CheckDisposed(); + // Can't call Start twice + Contract.Assert(_appFunc == null); + + Contract.Assert(app != null); + Contract.Assert(addresses != null); + Contract.Assert(capabilities != null); + + _appFunc = app; + _capabilities = capabilities; + _logger = LogHelper.CreateLogger(loggerFactory, typeof(OwinWebListener)); + LogHelper.LogInfo(_logger, "Start"); + + foreach (var address in addresses) + { + // Build addresses from parts + var scheme = address.Get("scheme") ?? Constants.HttpScheme; + var host = address.Get("host") ?? "localhost"; + var port = address.Get("port") ?? "5000"; + var path = address.Get("path") ?? string.Empty; + + Prefix prefix = Prefix.Create(scheme, host, port, path); + _uriPrefixes.Add(prefix); + } + + // Make sure there are no race conditions between Start/Stop/Abort/Close/Dispose and + // calls to SetupV2Config: Start needs to setup all resources (esp. in V2 where besides + // the request handle, there is also a server session and a Url group. Abort/Stop must + // not interfere while Start is allocating those resources. The lock also makes sure + // all methods changing state can read and change the state in an atomic way. + lock (_internalLock) + { + try + { + CheckDisposed(); + if (_state == State.Started) + { + return; + } + + // SetupV2Config() is not called in the ctor, because it may throw. This would + // be a regression since in v1 the ctor never threw. Besides, ctors should do + // minimal work according to the framework design guidelines. + SetupV2Config(); + CreateRequestQueueHandle(); + AttachRequestQueueToUrlGroup(); + + // All resources are set up correctly. Now add all prefixes. + try + { + AddAllPrefixes(); + } + catch (WebListenerException) + { + // If an error occurred while adding prefixes, free all resources allocated by previous steps. + DetachRequestQueueFromUrlGroup(); + throw; + } + + _state = State.Started; + + SetRequestQueueLimit(); + + OffloadListenForNextRequestAsync(); + } + catch (Exception exception) + { + // Make sure the HttpListener instance can't be used if Start() failed. + _state = State.Disposed; + CloseRequestQueueHandle(); + CleanupV2Config(); + LogHelper.LogException(_logger, "Start", exception); + throw; + } + } + } + + // Make sure the next request is processed on another thread as to not recursively + // block the request we just received. + private void OffloadListenForNextRequestAsync() + { + if (IsListening && CanAcceptMoreRequests) + { + Task offloadTask = Task.Run(_offloadListenForNextRequest); + } + } + + // The message pump. + // When we start listening for the next request on one thread, we may need to be sure that the + // completion continues on another thread as to not block the current request processing. + // The awaits will manage stack depth for us. + private async void ListenForNextRequestAsync() + { + while (IsListening && CanAcceptMoreRequests) + { + // Receive a request + RequestContext requestContext; + Interlocked.Increment(ref _currentOutstandingAccepts); + try + { + requestContext = await GetContextAsync().SupressContext(); + Interlocked.Decrement(ref _currentOutstandingAccepts); + } + catch (Exception exception) + { + LogHelper.LogException(_logger, "ListenForNextRequestAsync", exception); + // Assume the server has stopped. + Interlocked.Decrement(ref _currentOutstandingAccepts); + Contract.Assert(!IsListening); + return; + } + + Interlocked.Increment(ref _currentOutstandingRequests); + OffloadListenForNextRequestAsync(); + await ProcessRequestAsync(requestContext).SupressContext(); + Interlocked.Decrement(ref _currentOutstandingRequests); + } + } + + private async Task ProcessRequestAsync(RequestContext requestContext) + { + try + { + try + { + // TODO: Make disconnect registration lazy + RegisterForDisconnectNotification(requestContext); + await _appFunc(requestContext.Environment).SupressContext(); + await requestContext.ProcessResponseAsync().SupressContext(); + } + catch (Exception ex) + { + LogHelper.LogException(_logger, "ProcessRequestAsync", ex); + if (requestContext.Response.SentHeaders) + { + requestContext.Abort(); + } + else + { + // We haven't sent a response yet, try to send a 500 Internal Server Error + requestContext.SetFatalResponse(); + } + } + requestContext.Dispose(); + } + catch (Exception ex) + { + LogHelper.LogException(_logger, "ProcessRequestAsync", ex); + requestContext.Abort(); + requestContext.Dispose(); + } + } + + private void CleanupV2Config() + { + // If we never setup V2, just return. + if (!_v2Initialized) + { + return; + } + + // V2 stopping sequence: + // 1. Detach request queue from url group - Done in Stop()/Abort() + // 2. Remove urls from url group - Done in Stop() + // 3. Close request queue - Done in Stop()/Abort() + // 4. Close Url group. + // 5. Close server session. + + Debug.Assert(_urlGroupId != 0, "HttpCloseUrlGroup called with invalid url group id"); + + uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpCloseUrlGroup(_urlGroupId); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + LogHelper.LogError(_logger, "CleanupV2Config", "Result: " + statusCode); + } + _urlGroupId = 0; + + Debug.Assert(_serverSessionHandle != null, "ServerSessionHandle is null in CloseV2Config"); + Debug.Assert(!_serverSessionHandle.IsInvalid, "ServerSessionHandle is invalid in CloseV2Config"); + + _serverSessionHandle.Dispose(); + } + + private unsafe void AttachRequestQueueToUrlGroup() + { + // Set the association between request queue and url group. After this, requests for registered urls will + // get delivered to this request queue. + + UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO info = new UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO(); + info.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + info.RequestQueueHandle = DangerousGetHandle(); + + IntPtr infoptr = new IntPtr(&info); + + SetUrlGroupProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + infoptr, (uint)BindingInfoSize); + } + + private unsafe void DetachRequestQueueFromUrlGroup() + { + Debug.Assert(_urlGroupId != 0, "DetachRequestQueueFromUrlGroup can't detach using Url group id 0."); + + // Break the association between request queue and url group. After this, requests for registered urls + // will get 503s. + // Note that this method may be called multiple times (Stop() and then Abort()). This + // is fine since http.sys allows to set HttpServerBindingProperty multiple times for valid + // Url groups. + + UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO info = new UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO(); + info.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + info.RequestQueueHandle = IntPtr.Zero; + + IntPtr infoptr = new IntPtr(&info); + + uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpSetUrlGroupProperty(_urlGroupId, + UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + infoptr, (uint)BindingInfoSize); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + LogHelper.LogError(_logger, "DetachRequestQueueFromUrlGroup", "Result: " + statusCode); + } + } + + internal void Stop() + { + try + { + lock (_internalLock) + { + CheckDisposed(); + if (_state == State.Stopped) + { + return; + } + LogHelper.LogInfo(_logger, "Stop"); + + RemoveAll(false); + + _state = State.Stopped; + + DetachRequestQueueFromUrlGroup(); + + // Even though it would be enough to just detach the request queue in v2, in order to + // keep app compat with earlier versions of the framework, we need to close the request queue. + // This will make sure that pending GetContext() calls will complete and throw an exception. Just + // detaching the url group from the request queue would not cause GetContext() to return. + CloseRequestQueueHandle(); + } + } + catch (Exception exception) + { + LogHelper.LogException(_logger, "Stop", exception); + throw; + } + } + + private unsafe void CreateRequestQueueHandle() + { + uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; + + HttpRequestQueueV2Handle requestQueueHandle = null; + statusCode = + UnsafeNclNativeMethods.SafeNetHandles.HttpCreateRequestQueue( + UnsafeNclNativeMethods.HttpApi.Version, null, null, 0, out requestQueueHandle); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new WebListenerException((int)statusCode); + } + + // Disabling callbacks when IO operation completes synchronously (returns ErrorCodes.ERROR_SUCCESS) + if (SkipIOCPCallbackOnSuccess && + !UnsafeNclNativeMethods.SetFileCompletionNotificationModes( + requestQueueHandle, + UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipCompletionPortOnSuccess | + UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipSetEventOnHandle)) + { + throw new WebListenerException(Marshal.GetLastWin32Error()); + } + + _requestQueueHandle = requestQueueHandle; + ThreadPool.BindHandle(_requestQueueHandle); + } + + private unsafe void CloseRequestQueueHandle() + { + if ((_requestQueueHandle != null) && (!_requestQueueHandle.IsInvalid)) + { + _requestQueueHandle.Dispose(); + } + } + + /// + /// Stop the server and clean up. + /// + public void Dispose() + { + Dispose(true); + } + + // old API, now private, and helper methods + private void Dispose(bool disposing) + { + if (!disposing) + { + return; + } + + lock (_internalLock) + { + try + { + if (_state == State.Disposed) + { + return; + } + LogHelper.LogInfo(_logger, "Dispose"); + + Stop(); + CleanupV2Config(); + } + catch (Exception exception) + { + LogHelper.LogException(_logger, "Dispose", exception); + throw; + } + finally + { + _state = State.Disposed; + } + } + } + + private uint InternalAddPrefix(string uriPrefix, int contextId) + { + uint statusCode = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup( + _urlGroupId, + uriPrefix, + (ulong)contextId, + 0); + + return statusCode; + } + + private bool InternalRemovePrefix(string uriPrefix) + { + uint statusCode = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup( + _urlGroupId, + uriPrefix, + 0); + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) + { + return false; + } + return true; + } + + private void AddAllPrefixes() + { + // go through the uri list and register for each one of them + if (_uriPrefixes.Count > 0) + { + for (int i = 0; i < _uriPrefixes.Count; i++) + { + // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. + Prefix registeredPrefix = _uriPrefixes[i]; + uint statusCode = InternalAddPrefix(registeredPrefix.Whole, i); + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS) + { + throw new WebListenerException((int)statusCode, String.Format(Resources.Exception_PrefixAlreadyRegistered, registeredPrefix.Whole)); + } + else + { + throw new WebListenerException((int)statusCode); + } + } + } + } + } + + internal unsafe bool ValidateRequest(NativeRequestContext requestMemory) + { + // Block potential DOS attacks + if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit) + { + SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest); + return false; + } + return true; + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by callback")] + internal Task GetContextAsync() + { + AsyncAcceptContext asyncResult = null; + try + { + CheckDisposed(); + Debug.Assert(_state != State.Stopped, "Listener has been stopped."); + // 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) + asyncResult = new AsyncAcceptContext(this); + uint statusCode = asyncResult.QueueBeginGetContext(); + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + // someother bad error, possible(?) return values are: + // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED + asyncResult.Dispose(); + throw new WebListenerException((int)statusCode); + } + } + catch (Exception exception) + { + LogHelper.LogException(_logger, "GetContextAsync", exception); + throw; + } + + return asyncResult.Task; + } + + private void RegisterForDisconnectNotification(RequestContext requestContext) + { + try + { + // Create exactly one CancellationToken per connection. + ulong connectionId = requestContext.Request.ConnectionId; + CancellationToken ct = GetConnectionCancellation(connectionId); + requestContext.Request.RegisterForDisconnect(ct); + requestContext.Environment.ConnectionDisconnect = ct; + } + catch (Win32Exception exception) + { + LogHelper.LogException(_logger, "RegisterForDisconnectNotification", exception); + } + } + + private CancellationToken GetConnectionCancellation(ulong connectionId) + { + // Read case is performance senstive + ConnectionCancellation cancellation; + if (!_connectionCancellationTokens.TryGetValue(connectionId, out cancellation)) + { + cancellation = GetCreatedConnectionCancellation(connectionId); + } + return cancellation.GetCancellationToken(connectionId); + } + + private ConnectionCancellation GetCreatedConnectionCancellation(ulong connectionId) + { + // Race condition on creation has no side effects + ConnectionCancellation cancellation = new ConnectionCancellation(this); + return _connectionCancellationTokens.GetOrAdd(connectionId, cancellation); + } + + private unsafe CancellationToken CreateDisconnectToken(ulong connectionId) + { + // Debug.WriteLine("Server: Registering connection for disconnect for connection ID: " + connectionId); + + // Create a nativeOverlapped callback so we can register for disconnect callback + var overlapped = new Overlapped(); + var cts = new CancellationTokenSource(); + + SafeNativeOverlapped nativeOverlapped = null; + nativeOverlapped = new SafeNativeOverlapped(overlapped.UnsafePack( + (errorCode, numBytes, overlappedPtr) => + { + // Debug.WriteLine("Server: http.sys disconnect callback fired for connection ID: " + connectionId); + + // Free the overlapped + nativeOverlapped.Dispose(); + + // Pull the token out of the list and Cancel it. + ConnectionCancellation token; + _connectionCancellationTokens.TryRemove(connectionId, out token); + try + { + cts.Cancel(); + } + catch (AggregateException exception) + { + LogHelper.LogException(_logger, "CreateDisconnectToken::Disconnected", exception); + } + + cts.Dispose(); + }, + null)); + + uint statusCode; + try + { + statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect(_requestQueueHandle, connectionId, nativeOverlapped); + } + catch (Win32Exception exception) + { + statusCode = (uint)exception.NativeErrorCode; + LogHelper.LogException(_logger, "CreateDisconnectToken", exception); + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING && + statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + // We got an unknown result so return a None + // TODO: return a canceled token? + return CancellationToken.None; + } + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + // TODO: return a canceled token? + return CancellationToken.None; + } + + return cts.Token; + } + + private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode) + { + UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE(); + httpResponse.Version = new UnsafeNclNativeMethods.HttpApi.HTTP_VERSION(); + httpResponse.Version.MajorVersion = (ushort)1; + httpResponse.Version.MinorVersion = (ushort)1; + httpResponse.StatusCode = (ushort)httpStatusCode; + string statusDescription = HttpReasonPhrase.Get(httpStatusCode); + uint dataWritten = 0; + uint statusCode; + byte[] byteReason = HeaderEncoding.GetBytes(statusDescription); + fixed (byte* pReason = byteReason) + { + httpResponse.pReason = (sbyte*)pReason; + httpResponse.ReasonLength = (ushort)byteReason.Length; + + byte[] byteContentLength = new byte[] { (byte)'0' }; + fixed (byte* pContentLength = byteContentLength) + { + (&httpResponse.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength; + (&httpResponse.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; + httpResponse.Headers.UnknownHeaderCount = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( + _requestQueueHandle, + requestId, + 0, + &httpResponse, + null, + &dataWritten, + SafeLocalFree.Zero, + 0, + SafeNativeOverlapped.Zero, + IntPtr.Zero); + } + } + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + // if we fail to send a 401 something's seriously wrong, abort the request + RequestContext.CancelRequest(_requestQueueHandle, requestId); + } + } + + private static int GetTokenOffsetFromBlob(IntPtr blob) + { + Debug.Assert(blob != IntPtr.Zero); +#if NET45 + IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelToken")); +#else + IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); +#endif + Debug.Assert(tokenPointer != IntPtr.Zero); + return (int)IntPtrHelper.Subtract(tokenPointer, blob); + } + + private static int GetTokenSizeFromBlob(IntPtr blob) + { + Debug.Assert(blob != IntPtr.Zero); +#if NET45 + return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelTokenSize")); +#else + return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); +#endif + } + + internal ChannelBinding GetChannelBinding(ulong connectionId, bool isSecureConnection) + { + if (!isSecureConnection) + { + LogHelper.LogInfo(_logger, "Channel binding is not supported for HTTP."); + return null; + } + + ChannelBinding result = GetChannelBindingFromTls(connectionId); + + Debug.Assert(result != null, "GetChannelBindingFromTls returned null even though OS supposedly supports Extended Protection"); + LogHelper.LogInfo(_logger, "Channel binding retrieved."); + return result; + } + + private unsafe ChannelBinding GetChannelBindingFromTls(ulong connectionId) + { + // +128 since a CBT is usually <128 thus we need to call HRCC just once. If the CBT + // is >128 we will get ERROR_MORE_DATA and call again + int size = RequestChannelBindStatusSize + 128; + + Debug.Assert(size >= 0); + + byte[] blob = null; + SafeLocalFreeChannelBinding token = null; + + uint bytesReceived = 0; + uint statusCode; + + do + { + blob = new byte[size]; + fixed (byte* blobPtr = blob) + { + // Http.sys team: ServiceName will always be null if + // HTTP_RECEIVE_SECURE_CHANNEL_TOKEN flag is set. + statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( + RequestQueueHandle, + connectionId, + (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN, + blobPtr, + (uint)size, + &bytesReceived, + SafeNativeOverlapped.Zero); + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + int tokenOffset = GetTokenOffsetFromBlob((IntPtr)blobPtr); + int tokenSize = GetTokenSizeFromBlob((IntPtr)blobPtr); + Debug.Assert(tokenSize < Int32.MaxValue); + + token = SafeLocalFreeChannelBinding.LocalAlloc(tokenSize); + + Marshal.Copy(blob, tokenOffset, token.DangerousGetHandle(), tokenSize); + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) + { + int tokenSize = GetTokenSizeFromBlob((IntPtr)blobPtr); + Debug.Assert(tokenSize < Int32.MaxValue); + + size = RequestChannelBindStatusSize + tokenSize; + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER) + { + LogHelper.LogError(_logger, "GetChannelBindingFromTls", "Channel binding is not supported."); + return null; // old schannel library which doesn't support CBT + } + else + { + // It's up to the consumer to fail if the missing ChannelBinding matters to them. + LogHelper.LogException(_logger, "GetChannelBindingFromTls", new WebListenerException((int)statusCode)); + break; + } + } + } + while (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); + + return token; + } + + internal void CheckDisposed() + { + if (_state == State.Disposed) + { + throw new ObjectDisposedException(this.GetType().FullName); + } + } + + private class ConnectionCancellation + { + private readonly OwinWebListener _parent; + private volatile bool _initialized; // Must be volatile because initialization is synchronized + private CancellationToken _cancellationToken; + + public ConnectionCancellation(OwinWebListener parent) + { + _parent = parent; + } + + internal CancellationToken GetCancellationToken(ulong connectionId) + { + // Initialized case is performance sensitive + if (_initialized) + { + return _cancellationToken; + } + return InitializeCancellationToken(connectionId); + } + + private CancellationToken InitializeCancellationToken(ulong connectionId) + { + object syncObject = this; +#pragma warning disable 420 // Disable warning about volatile by reference since EnsureInitialized does volatile operations + return LazyInitializer.EnsureInitialized(ref _cancellationToken, ref _initialized, ref syncObject, () => _parent.CreateDisconnectToken(connectionId)); +#pragma warning restore 420 + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/Prefix.cs b/src/Microsoft.AspNet.Server.WebListener/Prefix.cs new file mode 100644 index 0000000000..08a0fe61c5 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/Prefix.cs @@ -0,0 +1,102 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Globalization; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class Prefix + { + private Prefix(bool isHttps, string scheme, string host, string port, int portValue, string path) + { + IsHttps = isHttps; + Scheme = scheme; + Host = host; + Port = port; + PortValue = portValue; + Path = path; + Whole = string.Format(CultureInfo.InvariantCulture, "{0}://{1}:{2}{3}", Scheme, Host, Port, Path); + } + + /// + /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa364698(v=vs.85).aspx + /// + /// http or https. Will be normalized to lower case. + /// +, *, IPv4, [IPv6], or a dns name. Http.Sys does not permit punycode (xn--), use Unicode instead. + /// If empty, the default port for the given scheme will be used (80 or 443). + /// Should start and end with a '/', though a missing trailing slash will be added. This value must be un-escaped. + public static Prefix Create(string scheme, string host, string port, string path) + { + bool isHttps; + if (string.Equals(Constants.HttpScheme, scheme, StringComparison.OrdinalIgnoreCase)) + { + scheme = Constants.HttpScheme; // Always use a lower case scheme + isHttps = false; + } + else if (string.Equals(Constants.HttpsScheme, scheme, StringComparison.OrdinalIgnoreCase)) + { + scheme = Constants.HttpsScheme; // Always use a lower case scheme + isHttps = true; + } + else + { + throw new ArgumentOutOfRangeException("scheme", scheme, Resources.Exception_UnsupportedScheme); + } + + if (string.IsNullOrWhiteSpace(host)) + { + throw new ArgumentNullException("host"); + } + + int portValue; + if (string.IsNullOrWhiteSpace(port)) + { + port = isHttps ? "443" : "80"; + portValue = isHttps ? 443 : 80; + } + else + { + portValue = int.Parse(port, NumberStyles.None, CultureInfo.InvariantCulture); + } + + // Http.Sys requires the path end with a slash. + if (string.IsNullOrWhiteSpace(path)) + { + path = "/"; + } + else if (!path.EndsWith("/", StringComparison.Ordinal)) + { + path += "/"; + } + + return new Prefix(isHttps, scheme, host, port, portValue, path); + } + + public bool IsHttps { get; private set; } + public string Scheme { get; private set; } + public string Host { get; private set; } + public string Port { get; private set; } + public int PortValue { get; private set; } + public string Path { get; private set; } + public string Whole { get; private set; } + + public override bool Equals(object obj) + { + return string.Equals(Whole, obj as string, StringComparison.OrdinalIgnoreCase); + } + + public override int GetHashCode() + { + return StringComparer.OrdinalIgnoreCase.GetHashCode(Whole); + } + + public override string ToString() + { + return Whole; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..ed361b4f1c --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs @@ -0,0 +1,44 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.AspNet.Server.WebListener")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.AspNet.Server.WebListener")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1f471909-581f-4060-a147-430891e9c3c1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("0.5")] +[assembly: AssemblyVersion("0.5")] +[assembly: AssemblyFileVersion("0.5.40117.0")] +[assembly: CLSCompliant(true)] diff --git a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs b/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs new file mode 100644 index 0000000000..28b99c11cc --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs @@ -0,0 +1,31 @@ +// +// Copyright 2011-2012 Katana contributors +// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class PumpLimits + { + internal PumpLimits(int maxAccepts, int maxRequests) + { + MaxOutstandingAccepts = maxAccepts; + MaxOutstandingRequests = maxRequests; + } + + internal int MaxOutstandingAccepts { get; private set; } + + internal int MaxOutstandingRequests { get; private set; } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs new file mode 100644 index 0000000000..6d9ca0b4e2 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs @@ -0,0 +1,18 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Server.WebListener +{ + internal enum BoundaryType + { + ContentLength = 0, // Content-Length: XXX + Chunked = 1, // Transfer-Encoding: chunked + Raw = 2, // the app is responsible for sending the correct headers and body encoding + Multipart = 3, + None = 4, + Invalid = 5, + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.cs new file mode 100644 index 0000000000..d0fe8d05ea --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.cs @@ -0,0 +1,1913 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Katana Contributors. All rights reserved. +// +//----------------------------------------------------------------------- +// + +using System; +using System.CodeDom.Compiler; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Security.Authentication.ExtendedProtection; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + using OpaqueUpgrade = Action, Func, Task>>; + + [GeneratedCode("TextTemplatingFileGenerator", "")] + internal partial class CallEnvironment + { + // Mark all fields with delay initialization support as set. + private UInt32 _flag0 = 0x43e00200u; + private UInt32 _flag1 = 0x1u; + // Mark all fields with delay initialization support as requiring initialization. + private UInt32 _initFlag0 = 0x43e00200u; + private UInt32 _initFlag1 = 0x1u; + + internal interface IPropertySource + { + Stream GetRequestBody(); + string GetRemoteIpAddress(); + string GetRemotePort(); + string GetLocalIpAddress(); + string GetLocalPort(); + bool GetIsLocal(); + bool TryGetChannelBinding(ref ChannelBinding value); + bool TryGetOpaqueUpgrade(ref OpaqueUpgrade value); + } + + private string _OwinVersion; + private CancellationToken _CallCancelled; + private string _RequestProtocol; + private string _RequestMethod; + private string _RequestScheme; + private string _RequestPathBase; + private string _RequestPath; + private string _RequestQueryString; + private IDictionary _RequestHeaders; + private Stream _RequestBody; + private IDictionary _ResponseHeaders; + private Stream _ResponseBody; + private int? _ResponseStatusCode; + private string _ResponseReasonPhrase; + private TextWriter _HostTraceOutput; + private string _HostAppName; + private string _HostAppMode; + private CancellationToken _OnAppDisposing; + private System.Security.Principal.IPrincipal _User; + private Action, object> _OnSendingHeaders; + private IDictionary _ServerCapabilities; + private string _RemoteIpAddress; + private string _RemotePort; + private string _LocalIpAddress; + private string _LocalPort; + private bool _IsLocal; + private object _ConnectionId; + private CancellationToken _ConnectionDisconnect; + private object _ClientCert; + private Func _LoadClientCert; + private ChannelBinding _ChannelBinding; + private Func _SendFileAsync; + private OpaqueUpgrade _OpaqueUpgrade; + private OwinWebListener _Listener; + + bool InitPropertyChannelBinding() + { + if (!_propertySource.TryGetChannelBinding(ref _ChannelBinding)) + { + _flag0 &= ~0x40000000u; + _initFlag0 &= ~0x40000000u; + return false; + } + _initFlag0 &= ~0x40000000u; + return true; + } + + bool InitPropertyOpaqueUpgrade() + { + if (!_propertySource.TryGetOpaqueUpgrade(ref _OpaqueUpgrade)) + { + _flag1 &= ~0x1u; + _initFlag1 &= ~0x1u; + return false; + } + _initFlag1 &= ~0x1u; + return true; + } + + internal string OwinVersion + { + get + { + return _OwinVersion; + } + set + { + _flag0 |= 0x1u; + _OwinVersion = value; + } + } + + internal CancellationToken CallCancelled + { + get + { + return _CallCancelled; + } + set + { + _flag0 |= 0x2u; + _CallCancelled = value; + } + } + + internal string RequestProtocol + { + get + { + return _RequestProtocol; + } + set + { + _flag0 |= 0x4u; + _RequestProtocol = value; + } + } + + internal string RequestMethod + { + get + { + return _RequestMethod; + } + set + { + _flag0 |= 0x8u; + _RequestMethod = value; + } + } + + internal string RequestScheme + { + get + { + return _RequestScheme; + } + set + { + _flag0 |= 0x10u; + _RequestScheme = value; + } + } + + internal string RequestPathBase + { + get + { + return _RequestPathBase; + } + set + { + _flag0 |= 0x20u; + _RequestPathBase = value; + } + } + + internal string RequestPath + { + get + { + return _RequestPath; + } + set + { + _flag0 |= 0x40u; + _RequestPath = value; + } + } + + internal string RequestQueryString + { + get + { + return _RequestQueryString; + } + set + { + _flag0 |= 0x80u; + _RequestQueryString = value; + } + } + + internal IDictionary RequestHeaders + { + get + { + return _RequestHeaders; + } + set + { + _flag0 |= 0x100u; + _RequestHeaders = value; + } + } + + internal Stream RequestBody + { + get + { + if (((_initFlag0 & 0x200u) != 0)) + { + _RequestBody = _propertySource.GetRequestBody(); + _initFlag0 &= ~0x200u; + } + return _RequestBody; + } + set + { + _initFlag0 &= ~0x200u; + _flag0 |= 0x200u; + _RequestBody = value; + } + } + + internal IDictionary ResponseHeaders + { + get + { + return _ResponseHeaders; + } + set + { + _flag0 |= 0x400u; + _ResponseHeaders = value; + } + } + + internal Stream ResponseBody + { + get + { + return _ResponseBody; + } + set + { + _flag0 |= 0x800u; + _ResponseBody = value; + } + } + + internal int? ResponseStatusCode + { + get + { + return _ResponseStatusCode; + } + set + { + _flag0 |= 0x1000u; + _ResponseStatusCode = value; + } + } + + internal string ResponseReasonPhrase + { + get + { + return _ResponseReasonPhrase; + } + set + { + _flag0 |= 0x2000u; + _ResponseReasonPhrase = value; + } + } + + internal TextWriter HostTraceOutput + { + get + { + return _HostTraceOutput; + } + set + { + _flag0 |= 0x4000u; + _HostTraceOutput = value; + } + } + + internal string HostAppName + { + get + { + return _HostAppName; + } + set + { + _flag0 |= 0x8000u; + _HostAppName = value; + } + } + + internal string HostAppMode + { + get + { + return _HostAppMode; + } + set + { + _flag0 |= 0x10000u; + _HostAppMode = value; + } + } + + internal CancellationToken OnAppDisposing + { + get + { + return _OnAppDisposing; + } + set + { + _flag0 |= 0x20000u; + _OnAppDisposing = value; + } + } + + internal System.Security.Principal.IPrincipal User + { + get + { + return _User; + } + set + { + _flag0 |= 0x40000u; + _User = value; + } + } + + internal Action, object> OnSendingHeaders + { + get + { + return _OnSendingHeaders; + } + set + { + _flag0 |= 0x80000u; + _OnSendingHeaders = value; + } + } + + internal IDictionary ServerCapabilities + { + get + { + return _ServerCapabilities; + } + set + { + _flag0 |= 0x100000u; + _ServerCapabilities = value; + } + } + + internal string RemoteIpAddress + { + get + { + if (((_initFlag0 & 0x200000u) != 0)) + { + _RemoteIpAddress = _propertySource.GetRemoteIpAddress(); + _initFlag0 &= ~0x200000u; + } + return _RemoteIpAddress; + } + set + { + _initFlag0 &= ~0x200000u; + _flag0 |= 0x200000u; + _RemoteIpAddress = value; + } + } + + internal string RemotePort + { + get + { + if (((_initFlag0 & 0x400000u) != 0)) + { + _RemotePort = _propertySource.GetRemotePort(); + _initFlag0 &= ~0x400000u; + } + return _RemotePort; + } + set + { + _initFlag0 &= ~0x400000u; + _flag0 |= 0x400000u; + _RemotePort = value; + } + } + + internal string LocalIpAddress + { + get + { + if (((_initFlag0 & 0x800000u) != 0)) + { + _LocalIpAddress = _propertySource.GetLocalIpAddress(); + _initFlag0 &= ~0x800000u; + } + return _LocalIpAddress; + } + set + { + _initFlag0 &= ~0x800000u; + _flag0 |= 0x800000u; + _LocalIpAddress = value; + } + } + + internal string LocalPort + { + get + { + if (((_initFlag0 & 0x1000000u) != 0)) + { + _LocalPort = _propertySource.GetLocalPort(); + _initFlag0 &= ~0x1000000u; + } + return _LocalPort; + } + set + { + _initFlag0 &= ~0x1000000u; + _flag0 |= 0x1000000u; + _LocalPort = value; + } + } + + internal bool IsLocal + { + get + { + if (((_initFlag0 & 0x2000000u) != 0)) + { + _IsLocal = _propertySource.GetIsLocal(); + _initFlag0 &= ~0x2000000u; + } + return _IsLocal; + } + set + { + _initFlag0 &= ~0x2000000u; + _flag0 |= 0x2000000u; + _IsLocal = value; + } + } + + internal object ConnectionId + { + get + { + return _ConnectionId; + } + set + { + _flag0 |= 0x4000000u; + _ConnectionId = value; + } + } + + internal CancellationToken ConnectionDisconnect + { + get + { + return _ConnectionDisconnect; + } + set + { + _flag0 |= 0x8000000u; + _ConnectionDisconnect = value; + } + } + + internal object ClientCert + { + get + { + return _ClientCert; + } + set + { + _flag0 |= 0x10000000u; + _ClientCert = value; + } + } + + internal Func LoadClientCert + { + get + { + return _LoadClientCert; + } + set + { + _flag0 |= 0x20000000u; + _LoadClientCert = value; + } + } + + internal ChannelBinding ChannelBinding + { + get + { + if (((_initFlag0 & 0x40000000u) != 0)) + { + InitPropertyChannelBinding(); + } + return _ChannelBinding; + } + set + { + _initFlag0 &= ~0x40000000u; + _flag0 |= 0x40000000u; + _ChannelBinding = value; + } + } + + internal Func SendFileAsync + { + get + { + return _SendFileAsync; + } + set + { + _flag0 |= 0x80000000u; + _SendFileAsync = value; + } + } + + internal OpaqueUpgrade OpaqueUpgrade + { + get + { + if (((_initFlag1 & 0x1u) != 0)) + { + InitPropertyOpaqueUpgrade(); + } + return _OpaqueUpgrade; + } + set + { + _initFlag1 &= ~0x1u; + _flag1 |= 0x1u; + _OpaqueUpgrade = value; + } + } + + internal OwinWebListener Listener + { + get + { + return _Listener; + } + set + { + _flag1 |= 0x2u; + _Listener = value; + } + } + + private bool PropertiesContainsKey(string key) + { + switch (key.Length) + { + case 11: + if (((_flag0 & 0x40000u) != 0) && string.Equals(key, "server.User", StringComparison.Ordinal)) + { + return true; + } + break; + case 12: + if (((_flag0 & 0x1u) != 0) && string.Equals(key, "owin.Version", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x8000u) != 0) && string.Equals(key, "host.AppName", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x10000u) != 0) && string.Equals(key, "host.AppMode", StringComparison.Ordinal)) + { + return true; + } + break; + case 14: + if (((_flag0 & 0x2000000u) != 0) && string.Equals(key, "server.IsLocal", StringComparison.Ordinal)) + { + return true; + } + if (((_flag1 & 0x1u) != 0) && string.Equals(key, "opaque.Upgrade", StringComparison.Ordinal)) + { + if (((_initFlag1 & 0x1u) == 0) || InitPropertyOpaqueUpgrade()) + { + return true; + } + } + break; + case 16: + if (((_flag0 & 0x40u) != 0) && string.Equals(key, "owin.RequestPath", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x200u) != 0) && string.Equals(key, "owin.RequestBody", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x4000u) != 0) && string.Equals(key, "host.TraceOutput", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x1000000u) != 0) && string.Equals(key, "server.LocalPort", StringComparison.Ordinal)) + { + return true; + } + break; + case 17: + if (((_flag0 & 0x800u) != 0) && string.Equals(key, "owin.ResponseBody", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x400000u) != 0) && string.Equals(key, "server.RemotePort", StringComparison.Ordinal)) + { + return true; + } + break; + case 18: + if (((_flag0 & 0x2u) != 0) && string.Equals(key, "owin.CallCancelled", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x8u) != 0) && string.Equals(key, "owin.RequestMethod", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x10u) != 0) && string.Equals(key, "owin.RequestScheme", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x40000000u) != 0) && string.Equals(key, "ssl.ChannelBinding", StringComparison.Ordinal)) + { + if (((_initFlag0 & 0x40000000u) == 0) || InitPropertyChannelBinding()) + { + return true; + } + } + if (((_flag0 & 0x80000000u) != 0) && string.Equals(key, "sendfile.SendAsync", StringComparison.Ordinal)) + { + return true; + } + break; + case 19: + if (((_flag0 & 0x100u) != 0) && string.Equals(key, "owin.RequestHeaders", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x20000u) != 0) && string.Equals(key, "host.OnAppDisposing", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x100000u) != 0) && string.Equals(key, "server.Capabilities", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x4000000u) != 0) && string.Equals(key, "server.ConnectionId", StringComparison.Ordinal)) + { + return true; + } + break; + case 20: + if (((_flag0 & 0x4u) != 0) && string.Equals(key, "owin.RequestProtocol", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x20u) != 0) && string.Equals(key, "owin.RequestPathBase", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x400u) != 0) && string.Equals(key, "owin.ResponseHeaders", StringComparison.Ordinal)) + { + return true; + } + break; + case 21: + if (((_flag0 & 0x800000u) != 0) && string.Equals(key, "server.LocalIpAddress", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x10000000u) != 0) && string.Equals(key, "ssl.ClientCertificate", StringComparison.Ordinal)) + { + return true; + } + break; + case 22: + if (((_flag0 & 0x200000u) != 0) && string.Equals(key, "server.RemoteIpAddress", StringComparison.Ordinal)) + { + return true; + } + break; + case 23: + if (((_flag0 & 0x80u) != 0) && string.Equals(key, "owin.RequestQueryString", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x1000u) != 0) && string.Equals(key, "owin.ResponseStatusCode", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x80000u) != 0) && string.Equals(key, "server.OnSendingHeaders", StringComparison.Ordinal)) + { + return true; + } + if (((_flag0 & 0x20000000u) != 0) && string.Equals(key, "ssl.LoadClientCertAsync", StringComparison.Ordinal)) + { + return true; + } + break; + case 25: + if (((_flag0 & 0x2000u) != 0) && string.Equals(key, "owin.ResponseReasonPhrase", StringComparison.Ordinal)) + { + return true; + } + break; + case 27: + if (((_flag0 & 0x8000000u) != 0) && string.Equals(key, "server.ConnectionDisconnect", StringComparison.Ordinal)) + { + return true; + } + break; + case 51: + if (((_flag1 & 0x2u) != 0) && string.Equals(key, "Microsoft.AspNet.Server.WebListener.OwinWebListener", StringComparison.Ordinal)) + { + return true; + } + break; + } + return false; + } + + private bool PropertiesTryGetValue(string key, out object value) + { + switch (key.Length) + { + case 11: + if (((_flag0 & 0x40000u) != 0) && string.Equals(key, "server.User", StringComparison.Ordinal)) + { + value = User; + return true; + } + break; + case 12: + if (((_flag0 & 0x1u) != 0) && string.Equals(key, "owin.Version", StringComparison.Ordinal)) + { + value = OwinVersion; + return true; + } + if (((_flag0 & 0x8000u) != 0) && string.Equals(key, "host.AppName", StringComparison.Ordinal)) + { + value = HostAppName; + return true; + } + if (((_flag0 & 0x10000u) != 0) && string.Equals(key, "host.AppMode", StringComparison.Ordinal)) + { + value = HostAppMode; + return true; + } + break; + case 14: + if (((_flag0 & 0x2000000u) != 0) && string.Equals(key, "server.IsLocal", StringComparison.Ordinal)) + { + value = IsLocal; + return true; + } + if (((_flag1 & 0x1u) != 0) && string.Equals(key, "opaque.Upgrade", StringComparison.Ordinal)) + { + value = OpaqueUpgrade; + // Delayed initialization in the property getter may determine that the element is not actually present + if (!((_flag1 & 0x1u) != 0)) + { + value = default(OpaqueUpgrade); + return false; + } + return true; + } + break; + case 16: + if (((_flag0 & 0x40u) != 0) && string.Equals(key, "owin.RequestPath", StringComparison.Ordinal)) + { + value = RequestPath; + return true; + } + if (((_flag0 & 0x200u) != 0) && string.Equals(key, "owin.RequestBody", StringComparison.Ordinal)) + { + value = RequestBody; + return true; + } + if (((_flag0 & 0x4000u) != 0) && string.Equals(key, "host.TraceOutput", StringComparison.Ordinal)) + { + value = HostTraceOutput; + return true; + } + if (((_flag0 & 0x1000000u) != 0) && string.Equals(key, "server.LocalPort", StringComparison.Ordinal)) + { + value = LocalPort; + return true; + } + break; + case 17: + if (((_flag0 & 0x800u) != 0) && string.Equals(key, "owin.ResponseBody", StringComparison.Ordinal)) + { + value = ResponseBody; + return true; + } + if (((_flag0 & 0x400000u) != 0) && string.Equals(key, "server.RemotePort", StringComparison.Ordinal)) + { + value = RemotePort; + return true; + } + break; + case 18: + if (((_flag0 & 0x2u) != 0) && string.Equals(key, "owin.CallCancelled", StringComparison.Ordinal)) + { + value = CallCancelled; + return true; + } + if (((_flag0 & 0x8u) != 0) && string.Equals(key, "owin.RequestMethod", StringComparison.Ordinal)) + { + value = RequestMethod; + return true; + } + if (((_flag0 & 0x10u) != 0) && string.Equals(key, "owin.RequestScheme", StringComparison.Ordinal)) + { + value = RequestScheme; + return true; + } + if (((_flag0 & 0x40000000u) != 0) && string.Equals(key, "ssl.ChannelBinding", StringComparison.Ordinal)) + { + value = ChannelBinding; + // Delayed initialization in the property getter may determine that the element is not actually present + if (!((_flag0 & 0x40000000u) != 0)) + { + value = default(ChannelBinding); + return false; + } + return true; + } + if (((_flag0 & 0x80000000u) != 0) && string.Equals(key, "sendfile.SendAsync", StringComparison.Ordinal)) + { + value = SendFileAsync; + return true; + } + break; + case 19: + if (((_flag0 & 0x100u) != 0) && string.Equals(key, "owin.RequestHeaders", StringComparison.Ordinal)) + { + value = RequestHeaders; + return true; + } + if (((_flag0 & 0x20000u) != 0) && string.Equals(key, "host.OnAppDisposing", StringComparison.Ordinal)) + { + value = OnAppDisposing; + return true; + } + if (((_flag0 & 0x100000u) != 0) && string.Equals(key, "server.Capabilities", StringComparison.Ordinal)) + { + value = ServerCapabilities; + return true; + } + if (((_flag0 & 0x4000000u) != 0) && string.Equals(key, "server.ConnectionId", StringComparison.Ordinal)) + { + value = ConnectionId; + return true; + } + break; + case 20: + if (((_flag0 & 0x4u) != 0) && string.Equals(key, "owin.RequestProtocol", StringComparison.Ordinal)) + { + value = RequestProtocol; + return true; + } + if (((_flag0 & 0x20u) != 0) && string.Equals(key, "owin.RequestPathBase", StringComparison.Ordinal)) + { + value = RequestPathBase; + return true; + } + if (((_flag0 & 0x400u) != 0) && string.Equals(key, "owin.ResponseHeaders", StringComparison.Ordinal)) + { + value = ResponseHeaders; + return true; + } + break; + case 21: + if (((_flag0 & 0x800000u) != 0) && string.Equals(key, "server.LocalIpAddress", StringComparison.Ordinal)) + { + value = LocalIpAddress; + return true; + } + if (((_flag0 & 0x10000000u) != 0) && string.Equals(key, "ssl.ClientCertificate", StringComparison.Ordinal)) + { + value = ClientCert; + return true; + } + break; + case 22: + if (((_flag0 & 0x200000u) != 0) && string.Equals(key, "server.RemoteIpAddress", StringComparison.Ordinal)) + { + value = RemoteIpAddress; + return true; + } + break; + case 23: + if (((_flag0 & 0x80u) != 0) && string.Equals(key, "owin.RequestQueryString", StringComparison.Ordinal)) + { + value = RequestQueryString; + return true; + } + if (((_flag0 & 0x1000u) != 0) && string.Equals(key, "owin.ResponseStatusCode", StringComparison.Ordinal)) + { + value = ResponseStatusCode; + return true; + } + if (((_flag0 & 0x80000u) != 0) && string.Equals(key, "server.OnSendingHeaders", StringComparison.Ordinal)) + { + value = OnSendingHeaders; + return true; + } + if (((_flag0 & 0x20000000u) != 0) && string.Equals(key, "ssl.LoadClientCertAsync", StringComparison.Ordinal)) + { + value = LoadClientCert; + return true; + } + break; + case 25: + if (((_flag0 & 0x2000u) != 0) && string.Equals(key, "owin.ResponseReasonPhrase", StringComparison.Ordinal)) + { + value = ResponseReasonPhrase; + return true; + } + break; + case 27: + if (((_flag0 & 0x8000000u) != 0) && string.Equals(key, "server.ConnectionDisconnect", StringComparison.Ordinal)) + { + value = ConnectionDisconnect; + return true; + } + break; + case 51: + if (((_flag1 & 0x2u) != 0) && string.Equals(key, "Microsoft.AspNet.Server.WebListener.OwinWebListener", StringComparison.Ordinal)) + { + value = Listener; + return true; + } + break; + } + value = null; + return false; + } + + private bool PropertiesTrySetValue(string key, object value) + { + switch (key.Length) + { + case 11: + if (string.Equals(key, "server.User", StringComparison.Ordinal)) + { + User = (System.Security.Principal.IPrincipal)value; + return true; + } + break; + case 12: + if (string.Equals(key, "owin.Version", StringComparison.Ordinal)) + { + OwinVersion = (string)value; + return true; + } + if (string.Equals(key, "host.AppName", StringComparison.Ordinal)) + { + HostAppName = (string)value; + return true; + } + if (string.Equals(key, "host.AppMode", StringComparison.Ordinal)) + { + HostAppMode = (string)value; + return true; + } + break; + case 14: + if (string.Equals(key, "server.IsLocal", StringComparison.Ordinal)) + { + IsLocal = (bool)value; + return true; + } + if (string.Equals(key, "opaque.Upgrade", StringComparison.Ordinal)) + { + OpaqueUpgrade = (OpaqueUpgrade)value; + return true; + } + break; + case 16: + if (string.Equals(key, "owin.RequestPath", StringComparison.Ordinal)) + { + RequestPath = (string)value; + return true; + } + if (string.Equals(key, "owin.RequestBody", StringComparison.Ordinal)) + { + RequestBody = (Stream)value; + return true; + } + if (string.Equals(key, "host.TraceOutput", StringComparison.Ordinal)) + { + HostTraceOutput = (TextWriter)value; + return true; + } + if (string.Equals(key, "server.LocalPort", StringComparison.Ordinal)) + { + LocalPort = (string)value; + return true; + } + break; + case 17: + if (string.Equals(key, "owin.ResponseBody", StringComparison.Ordinal)) + { + ResponseBody = (Stream)value; + return true; + } + if (string.Equals(key, "server.RemotePort", StringComparison.Ordinal)) + { + RemotePort = (string)value; + return true; + } + break; + case 18: + if (string.Equals(key, "owin.CallCancelled", StringComparison.Ordinal)) + { + CallCancelled = (CancellationToken)value; + return true; + } + if (string.Equals(key, "owin.RequestMethod", StringComparison.Ordinal)) + { + RequestMethod = (string)value; + return true; + } + if (string.Equals(key, "owin.RequestScheme", StringComparison.Ordinal)) + { + RequestScheme = (string)value; + return true; + } + if (string.Equals(key, "ssl.ChannelBinding", StringComparison.Ordinal)) + { + ChannelBinding = (ChannelBinding)value; + return true; + } + if (string.Equals(key, "sendfile.SendAsync", StringComparison.Ordinal)) + { + SendFileAsync = (Func)value; + return true; + } + break; + case 19: + if (string.Equals(key, "owin.RequestHeaders", StringComparison.Ordinal)) + { + RequestHeaders = (IDictionary)value; + return true; + } + if (string.Equals(key, "host.OnAppDisposing", StringComparison.Ordinal)) + { + OnAppDisposing = (CancellationToken)value; + return true; + } + if (string.Equals(key, "server.Capabilities", StringComparison.Ordinal)) + { + ServerCapabilities = (IDictionary)value; + return true; + } + if (string.Equals(key, "server.ConnectionId", StringComparison.Ordinal)) + { + ConnectionId = (object)value; + return true; + } + break; + case 20: + if (string.Equals(key, "owin.RequestProtocol", StringComparison.Ordinal)) + { + RequestProtocol = (string)value; + return true; + } + if (string.Equals(key, "owin.RequestPathBase", StringComparison.Ordinal)) + { + RequestPathBase = (string)value; + return true; + } + if (string.Equals(key, "owin.ResponseHeaders", StringComparison.Ordinal)) + { + ResponseHeaders = (IDictionary)value; + return true; + } + break; + case 21: + if (string.Equals(key, "server.LocalIpAddress", StringComparison.Ordinal)) + { + LocalIpAddress = (string)value; + return true; + } + if (string.Equals(key, "ssl.ClientCertificate", StringComparison.Ordinal)) + { + ClientCert = (object)value; + return true; + } + break; + case 22: + if (string.Equals(key, "server.RemoteIpAddress", StringComparison.Ordinal)) + { + RemoteIpAddress = (string)value; + return true; + } + break; + case 23: + if (string.Equals(key, "owin.RequestQueryString", StringComparison.Ordinal)) + { + RequestQueryString = (string)value; + return true; + } + if (string.Equals(key, "owin.ResponseStatusCode", StringComparison.Ordinal)) + { + ResponseStatusCode = (int?)value; + return true; + } + if (string.Equals(key, "server.OnSendingHeaders", StringComparison.Ordinal)) + { + OnSendingHeaders = (Action, object>)value; + return true; + } + if (string.Equals(key, "ssl.LoadClientCertAsync", StringComparison.Ordinal)) + { + LoadClientCert = (Func)value; + return true; + } + break; + case 25: + if (string.Equals(key, "owin.ResponseReasonPhrase", StringComparison.Ordinal)) + { + ResponseReasonPhrase = (string)value; + return true; + } + break; + case 27: + if (string.Equals(key, "server.ConnectionDisconnect", StringComparison.Ordinal)) + { + ConnectionDisconnect = (CancellationToken)value; + return true; + } + break; + case 51: + if (string.Equals(key, "Microsoft.AspNet.Server.WebListener.OwinWebListener", StringComparison.Ordinal)) + { + Listener = (OwinWebListener)value; + return true; + } + break; + } + return false; + } + + private bool PropertiesTryRemove(string key) + { + switch (key.Length) + { + case 11: + if (((_flag0 & 0x40000u) != 0) && string.Equals(key, "server.User", StringComparison.Ordinal)) + { + _flag0 &= ~0x40000u; + _User = default(System.Security.Principal.IPrincipal); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 12: + if (((_flag0 & 0x1u) != 0) && string.Equals(key, "owin.Version", StringComparison.Ordinal)) + { + _flag0 &= ~0x1u; + _OwinVersion = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x8000u) != 0) && string.Equals(key, "host.AppName", StringComparison.Ordinal)) + { + _flag0 &= ~0x8000u; + _HostAppName = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x10000u) != 0) && string.Equals(key, "host.AppMode", StringComparison.Ordinal)) + { + _flag0 &= ~0x10000u; + _HostAppMode = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 14: + if (((_flag0 & 0x2000000u) != 0) && string.Equals(key, "server.IsLocal", StringComparison.Ordinal)) + { + _initFlag0 &= ~0x2000000u; + _flag0 &= ~0x2000000u; + _IsLocal = default(bool); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag1 & 0x1u) != 0) && string.Equals(key, "opaque.Upgrade", StringComparison.Ordinal)) + { + _initFlag1 &= ~0x1u; + _flag1 &= ~0x1u; + _OpaqueUpgrade = default(OpaqueUpgrade); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 16: + if (((_flag0 & 0x40u) != 0) && string.Equals(key, "owin.RequestPath", StringComparison.Ordinal)) + { + _flag0 &= ~0x40u; + _RequestPath = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x200u) != 0) && string.Equals(key, "owin.RequestBody", StringComparison.Ordinal)) + { + _initFlag0 &= ~0x200u; + _flag0 &= ~0x200u; + _RequestBody = default(Stream); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x4000u) != 0) && string.Equals(key, "host.TraceOutput", StringComparison.Ordinal)) + { + _flag0 &= ~0x4000u; + _HostTraceOutput = default(TextWriter); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x1000000u) != 0) && string.Equals(key, "server.LocalPort", StringComparison.Ordinal)) + { + _initFlag0 &= ~0x1000000u; + _flag0 &= ~0x1000000u; + _LocalPort = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 17: + if (((_flag0 & 0x800u) != 0) && string.Equals(key, "owin.ResponseBody", StringComparison.Ordinal)) + { + _flag0 &= ~0x800u; + _ResponseBody = default(Stream); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x400000u) != 0) && string.Equals(key, "server.RemotePort", StringComparison.Ordinal)) + { + _initFlag0 &= ~0x400000u; + _flag0 &= ~0x400000u; + _RemotePort = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 18: + if (((_flag0 & 0x2u) != 0) && string.Equals(key, "owin.CallCancelled", StringComparison.Ordinal)) + { + _flag0 &= ~0x2u; + _CallCancelled = default(CancellationToken); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x8u) != 0) && string.Equals(key, "owin.RequestMethod", StringComparison.Ordinal)) + { + _flag0 &= ~0x8u; + _RequestMethod = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x10u) != 0) && string.Equals(key, "owin.RequestScheme", StringComparison.Ordinal)) + { + _flag0 &= ~0x10u; + _RequestScheme = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x40000000u) != 0) && string.Equals(key, "ssl.ChannelBinding", StringComparison.Ordinal)) + { + _initFlag0 &= ~0x40000000u; + _flag0 &= ~0x40000000u; + _ChannelBinding = default(ChannelBinding); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x80000000u) != 0) && string.Equals(key, "sendfile.SendAsync", StringComparison.Ordinal)) + { + _flag0 &= ~0x80000000u; + _SendFileAsync = default(Func); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 19: + if (((_flag0 & 0x100u) != 0) && string.Equals(key, "owin.RequestHeaders", StringComparison.Ordinal)) + { + _flag0 &= ~0x100u; + _RequestHeaders = default(IDictionary); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x20000u) != 0) && string.Equals(key, "host.OnAppDisposing", StringComparison.Ordinal)) + { + _flag0 &= ~0x20000u; + _OnAppDisposing = default(CancellationToken); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x100000u) != 0) && string.Equals(key, "server.Capabilities", StringComparison.Ordinal)) + { + _flag0 &= ~0x100000u; + _ServerCapabilities = default(IDictionary); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x4000000u) != 0) && string.Equals(key, "server.ConnectionId", StringComparison.Ordinal)) + { + _flag0 &= ~0x4000000u; + _ConnectionId = default(object); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 20: + if (((_flag0 & 0x4u) != 0) && string.Equals(key, "owin.RequestProtocol", StringComparison.Ordinal)) + { + _flag0 &= ~0x4u; + _RequestProtocol = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x20u) != 0) && string.Equals(key, "owin.RequestPathBase", StringComparison.Ordinal)) + { + _flag0 &= ~0x20u; + _RequestPathBase = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x400u) != 0) && string.Equals(key, "owin.ResponseHeaders", StringComparison.Ordinal)) + { + _flag0 &= ~0x400u; + _ResponseHeaders = default(IDictionary); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 21: + if (((_flag0 & 0x800000u) != 0) && string.Equals(key, "server.LocalIpAddress", StringComparison.Ordinal)) + { + _initFlag0 &= ~0x800000u; + _flag0 &= ~0x800000u; + _LocalIpAddress = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x10000000u) != 0) && string.Equals(key, "ssl.ClientCertificate", StringComparison.Ordinal)) + { + _flag0 &= ~0x10000000u; + _ClientCert = default(object); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 22: + if (((_flag0 & 0x200000u) != 0) && string.Equals(key, "server.RemoteIpAddress", StringComparison.Ordinal)) + { + _initFlag0 &= ~0x200000u; + _flag0 &= ~0x200000u; + _RemoteIpAddress = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 23: + if (((_flag0 & 0x80u) != 0) && string.Equals(key, "owin.RequestQueryString", StringComparison.Ordinal)) + { + _flag0 &= ~0x80u; + _RequestQueryString = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x1000u) != 0) && string.Equals(key, "owin.ResponseStatusCode", StringComparison.Ordinal)) + { + _flag0 &= ~0x1000u; + _ResponseStatusCode = default(int?); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x80000u) != 0) && string.Equals(key, "server.OnSendingHeaders", StringComparison.Ordinal)) + { + _flag0 &= ~0x80000u; + _OnSendingHeaders = default(Action, object>); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + if (((_flag0 & 0x20000000u) != 0) && string.Equals(key, "ssl.LoadClientCertAsync", StringComparison.Ordinal)) + { + _flag0 &= ~0x20000000u; + _LoadClientCert = default(Func); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 25: + if (((_flag0 & 0x2000u) != 0) && string.Equals(key, "owin.ResponseReasonPhrase", StringComparison.Ordinal)) + { + _flag0 &= ~0x2000u; + _ResponseReasonPhrase = default(string); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 27: + if (((_flag0 & 0x8000000u) != 0) && string.Equals(key, "server.ConnectionDisconnect", StringComparison.Ordinal)) + { + _flag0 &= ~0x8000000u; + _ConnectionDisconnect = default(CancellationToken); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + case 51: + if (((_flag1 & 0x2u) != 0) && string.Equals(key, "Microsoft.AspNet.Server.WebListener.OwinWebListener", StringComparison.Ordinal)) + { + _flag1 &= ~0x2u; + _Listener = default(OwinWebListener); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } + break; + } + return false; + } + + private IEnumerable PropertiesKeys() + { + if (((_flag0 & 0x1u) != 0)) + { + yield return "owin.Version"; + } + if (((_flag0 & 0x2u) != 0)) + { + yield return "owin.CallCancelled"; + } + if (((_flag0 & 0x4u) != 0)) + { + yield return "owin.RequestProtocol"; + } + if (((_flag0 & 0x8u) != 0)) + { + yield return "owin.RequestMethod"; + } + if (((_flag0 & 0x10u) != 0)) + { + yield return "owin.RequestScheme"; + } + if (((_flag0 & 0x20u) != 0)) + { + yield return "owin.RequestPathBase"; + } + if (((_flag0 & 0x40u) != 0)) + { + yield return "owin.RequestPath"; + } + if (((_flag0 & 0x80u) != 0)) + { + yield return "owin.RequestQueryString"; + } + if (((_flag0 & 0x100u) != 0)) + { + yield return "owin.RequestHeaders"; + } + if (((_flag0 & 0x200u) != 0)) + { + yield return "owin.RequestBody"; + } + if (((_flag0 & 0x400u) != 0)) + { + yield return "owin.ResponseHeaders"; + } + if (((_flag0 & 0x800u) != 0)) + { + yield return "owin.ResponseBody"; + } + if (((_flag0 & 0x1000u) != 0)) + { + yield return "owin.ResponseStatusCode"; + } + if (((_flag0 & 0x2000u) != 0)) + { + yield return "owin.ResponseReasonPhrase"; + } + if (((_flag0 & 0x4000u) != 0)) + { + yield return "host.TraceOutput"; + } + if (((_flag0 & 0x8000u) != 0)) + { + yield return "host.AppName"; + } + if (((_flag0 & 0x10000u) != 0)) + { + yield return "host.AppMode"; + } + if (((_flag0 & 0x20000u) != 0)) + { + yield return "host.OnAppDisposing"; + } + if (((_flag0 & 0x40000u) != 0)) + { + yield return "server.User"; + } + if (((_flag0 & 0x80000u) != 0)) + { + yield return "server.OnSendingHeaders"; + } + if (((_flag0 & 0x100000u) != 0)) + { + yield return "server.Capabilities"; + } + if (((_flag0 & 0x200000u) != 0)) + { + yield return "server.RemoteIpAddress"; + } + if (((_flag0 & 0x400000u) != 0)) + { + yield return "server.RemotePort"; + } + if (((_flag0 & 0x800000u) != 0)) + { + yield return "server.LocalIpAddress"; + } + if (((_flag0 & 0x1000000u) != 0)) + { + yield return "server.LocalPort"; + } + if (((_flag0 & 0x2000000u) != 0)) + { + yield return "server.IsLocal"; + } + if (((_flag0 & 0x4000000u) != 0)) + { + yield return "server.ConnectionId"; + } + if (((_flag0 & 0x8000000u) != 0)) + { + yield return "server.ConnectionDisconnect"; + } + if (((_flag0 & 0x10000000u) != 0)) + { + yield return "ssl.ClientCertificate"; + } + if (((_flag0 & 0x20000000u) != 0)) + { + yield return "ssl.LoadClientCertAsync"; + } + if (((_flag0 & 0x40000000u) != 0)) + { + if (((_initFlag0 & 0x40000000u) == 0) || InitPropertyChannelBinding()) + { + yield return "ssl.ChannelBinding"; + } + } + if (((_flag0 & 0x80000000u) != 0)) + { + yield return "sendfile.SendAsync"; + } + if (((_flag1 & 0x1u) != 0)) + { + if (((_initFlag1 & 0x1u) == 0) || InitPropertyOpaqueUpgrade()) + { + yield return "opaque.Upgrade"; + } + } + if (((_flag1 & 0x2u) != 0)) + { + yield return "Microsoft.AspNet.Server.WebListener.OwinWebListener"; + } + } + + private IEnumerable PropertiesValues() + { + if (((_flag0 & 0x1u) != 0)) + { + yield return OwinVersion; + } + if (((_flag0 & 0x2u) != 0)) + { + yield return CallCancelled; + } + if (((_flag0 & 0x4u) != 0)) + { + yield return RequestProtocol; + } + if (((_flag0 & 0x8u) != 0)) + { + yield return RequestMethod; + } + if (((_flag0 & 0x10u) != 0)) + { + yield return RequestScheme; + } + if (((_flag0 & 0x20u) != 0)) + { + yield return RequestPathBase; + } + if (((_flag0 & 0x40u) != 0)) + { + yield return RequestPath; + } + if (((_flag0 & 0x80u) != 0)) + { + yield return RequestQueryString; + } + if (((_flag0 & 0x100u) != 0)) + { + yield return RequestHeaders; + } + if (((_flag0 & 0x200u) != 0)) + { + yield return RequestBody; + } + if (((_flag0 & 0x400u) != 0)) + { + yield return ResponseHeaders; + } + if (((_flag0 & 0x800u) != 0)) + { + yield return ResponseBody; + } + if (((_flag0 & 0x1000u) != 0)) + { + yield return ResponseStatusCode; + } + if (((_flag0 & 0x2000u) != 0)) + { + yield return ResponseReasonPhrase; + } + if (((_flag0 & 0x4000u) != 0)) + { + yield return HostTraceOutput; + } + if (((_flag0 & 0x8000u) != 0)) + { + yield return HostAppName; + } + if (((_flag0 & 0x10000u) != 0)) + { + yield return HostAppMode; + } + if (((_flag0 & 0x20000u) != 0)) + { + yield return OnAppDisposing; + } + if (((_flag0 & 0x40000u) != 0)) + { + yield return User; + } + if (((_flag0 & 0x80000u) != 0)) + { + yield return OnSendingHeaders; + } + if (((_flag0 & 0x100000u) != 0)) + { + yield return ServerCapabilities; + } + if (((_flag0 & 0x200000u) != 0)) + { + yield return RemoteIpAddress; + } + if (((_flag0 & 0x400000u) != 0)) + { + yield return RemotePort; + } + if (((_flag0 & 0x800000u) != 0)) + { + yield return LocalIpAddress; + } + if (((_flag0 & 0x1000000u) != 0)) + { + yield return LocalPort; + } + if (((_flag0 & 0x2000000u) != 0)) + { + yield return IsLocal; + } + if (((_flag0 & 0x4000000u) != 0)) + { + yield return ConnectionId; + } + if (((_flag0 & 0x8000000u) != 0)) + { + yield return ConnectionDisconnect; + } + if (((_flag0 & 0x10000000u) != 0)) + { + yield return ClientCert; + } + if (((_flag0 & 0x20000000u) != 0)) + { + yield return LoadClientCert; + } + if (((_flag0 & 0x40000000u) != 0)) + { + if (((_initFlag0 & 0x40000000u) == 0) || InitPropertyChannelBinding()) + { + yield return ChannelBinding; + } + } + if (((_flag0 & 0x80000000u) != 0)) + { + yield return SendFileAsync; + } + if (((_flag1 & 0x1u) != 0)) + { + if (((_initFlag1 & 0x1u) == 0) || InitPropertyOpaqueUpgrade()) + { + yield return OpaqueUpgrade; + } + } + if (((_flag1 & 0x2u) != 0)) + { + yield return Listener; + } + } + + private IEnumerable> PropertiesEnumerable() + { + if (((_flag0 & 0x1u) != 0)) + { + yield return new KeyValuePair("owin.Version", OwinVersion); + } + if (((_flag0 & 0x2u) != 0)) + { + yield return new KeyValuePair("owin.CallCancelled", CallCancelled); + } + if (((_flag0 & 0x4u) != 0)) + { + yield return new KeyValuePair("owin.RequestProtocol", RequestProtocol); + } + if (((_flag0 & 0x8u) != 0)) + { + yield return new KeyValuePair("owin.RequestMethod", RequestMethod); + } + if (((_flag0 & 0x10u) != 0)) + { + yield return new KeyValuePair("owin.RequestScheme", RequestScheme); + } + if (((_flag0 & 0x20u) != 0)) + { + yield return new KeyValuePair("owin.RequestPathBase", RequestPathBase); + } + if (((_flag0 & 0x40u) != 0)) + { + yield return new KeyValuePair("owin.RequestPath", RequestPath); + } + if (((_flag0 & 0x80u) != 0)) + { + yield return new KeyValuePair("owin.RequestQueryString", RequestQueryString); + } + if (((_flag0 & 0x100u) != 0)) + { + yield return new KeyValuePair("owin.RequestHeaders", RequestHeaders); + } + if (((_flag0 & 0x200u) != 0)) + { + yield return new KeyValuePair("owin.RequestBody", RequestBody); + } + if (((_flag0 & 0x400u) != 0)) + { + yield return new KeyValuePair("owin.ResponseHeaders", ResponseHeaders); + } + if (((_flag0 & 0x800u) != 0)) + { + yield return new KeyValuePair("owin.ResponseBody", ResponseBody); + } + if (((_flag0 & 0x1000u) != 0)) + { + yield return new KeyValuePair("owin.ResponseStatusCode", ResponseStatusCode); + } + if (((_flag0 & 0x2000u) != 0)) + { + yield return new KeyValuePair("owin.ResponseReasonPhrase", ResponseReasonPhrase); + } + if (((_flag0 & 0x4000u) != 0)) + { + yield return new KeyValuePair("host.TraceOutput", HostTraceOutput); + } + if (((_flag0 & 0x8000u) != 0)) + { + yield return new KeyValuePair("host.AppName", HostAppName); + } + if (((_flag0 & 0x10000u) != 0)) + { + yield return new KeyValuePair("host.AppMode", HostAppMode); + } + if (((_flag0 & 0x20000u) != 0)) + { + yield return new KeyValuePair("host.OnAppDisposing", OnAppDisposing); + } + if (((_flag0 & 0x40000u) != 0)) + { + yield return new KeyValuePair("server.User", User); + } + if (((_flag0 & 0x80000u) != 0)) + { + yield return new KeyValuePair("server.OnSendingHeaders", OnSendingHeaders); + } + if (((_flag0 & 0x100000u) != 0)) + { + yield return new KeyValuePair("server.Capabilities", ServerCapabilities); + } + if (((_flag0 & 0x200000u) != 0)) + { + yield return new KeyValuePair("server.RemoteIpAddress", RemoteIpAddress); + } + if (((_flag0 & 0x400000u) != 0)) + { + yield return new KeyValuePair("server.RemotePort", RemotePort); + } + if (((_flag0 & 0x800000u) != 0)) + { + yield return new KeyValuePair("server.LocalIpAddress", LocalIpAddress); + } + if (((_flag0 & 0x1000000u) != 0)) + { + yield return new KeyValuePair("server.LocalPort", LocalPort); + } + if (((_flag0 & 0x2000000u) != 0)) + { + yield return new KeyValuePair("server.IsLocal", IsLocal); + } + if (((_flag0 & 0x4000000u) != 0)) + { + yield return new KeyValuePair("server.ConnectionId", ConnectionId); + } + if (((_flag0 & 0x8000000u) != 0)) + { + yield return new KeyValuePair("server.ConnectionDisconnect", ConnectionDisconnect); + } + if (((_flag0 & 0x10000000u) != 0)) + { + yield return new KeyValuePair("ssl.ClientCertificate", ClientCert); + } + if (((_flag0 & 0x20000000u) != 0)) + { + yield return new KeyValuePair("ssl.LoadClientCertAsync", LoadClientCert); + } + if (((_flag0 & 0x40000000u) != 0)) + { + if (((_initFlag0 & 0x40000000u) == 0) || InitPropertyChannelBinding()) + { + yield return new KeyValuePair("ssl.ChannelBinding", ChannelBinding); + } + } + if (((_flag0 & 0x80000000u) != 0)) + { + yield return new KeyValuePair("sendfile.SendAsync", SendFileAsync); + } + if (((_flag1 & 0x1u) != 0)) + { + if (((_initFlag1 & 0x1u) == 0) || InitPropertyOpaqueUpgrade()) + { + yield return new KeyValuePair("opaque.Upgrade", OpaqueUpgrade); + } + } + if (((_flag1 & 0x2u) != 0)) + { + yield return new KeyValuePair("Microsoft.AspNet.Server.WebListener.OwinWebListener", Listener); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.tt b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.tt new file mode 100644 index 0000000000..41a1b3db06 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.tt @@ -0,0 +1,316 @@ +<#@ template language="C#" #> +<#@ assembly name="System.Core.dll" #> +<#@ import namespace="System.Linq" #> +<# +var Init = new {Yes = new object(), No = new object(), Maybe = new object()}; + +var props = new[] +{ +// owin standard keys + new {Key="owin.Version", Type="string", Name="OwinVersion", Init=Init.No}, + new {Key="owin.CallCancelled", Type="CancellationToken", Name="CallCancelled", Init=Init.No}, + + new {Key="owin.RequestProtocol", Type="string", Name="RequestProtocol", Init=Init.No}, + new {Key="owin.RequestMethod", Type="string", Name="RequestMethod", Init=Init.No}, + new {Key="owin.RequestScheme", Type="string", Name="RequestScheme", Init=Init.No}, + new {Key="owin.RequestPathBase", Type="string", Name="RequestPathBase", Init=Init.No}, + new {Key="owin.RequestPath", Type="string", Name="RequestPath", Init=Init.No}, + new {Key="owin.RequestQueryString", Type="string", Name="RequestQueryString", Init=Init.No}, + new {Key="owin.RequestHeaders", Type="IDictionary", Name="RequestHeaders", Init=Init.No}, + new {Key="owin.RequestBody", Type="Stream", Name="RequestBody", Init=Init.Yes}, + + new {Key="owin.ResponseHeaders", Type="IDictionary", Name="ResponseHeaders", Init=Init.No}, + new {Key="owin.ResponseBody", Type="Stream", Name="ResponseBody", Init=Init.No}, + new {Key="owin.ResponseStatusCode", Type="int?", Name="ResponseStatusCode", Init=Init.No}, + new {Key="owin.ResponseReasonPhrase", Type="string", Name="ResponseReasonPhrase", Init=Init.No}, + +// defacto host keys + new {Key="host.TraceOutput", Type="TextWriter", Name="HostTraceOutput", Init=Init.No}, + new {Key="host.AppName", Type="string", Name="HostAppName", Init=Init.No}, + new {Key="host.AppMode", Type="string", Name="HostAppMode", Init=Init.No}, + new {Key="host.OnAppDisposing", Type="CancellationToken", Name="OnAppDisposing", Init=Init.No}, + new {Key="server.User", Type="System.Security.Principal.IPrincipal", Name="User", Init=Init.No}, + new {Key="server.OnSendingHeaders", Type="Action, object>", Name="OnSendingHeaders", Init=Init.No}, + new {Key="server.Capabilities", Type="IDictionary", Name="ServerCapabilities", Init=Init.No}, + +// ServerVariable keys + new {Key="server.RemoteIpAddress", Type="string", Name="RemoteIpAddress", Init=Init.Yes}, + new {Key="server.RemotePort", Type="string", Name="RemotePort", Init=Init.Yes}, + new {Key="server.LocalIpAddress", Type="string", Name="LocalIpAddress", Init=Init.Yes}, + new {Key="server.LocalPort", Type="string", Name="LocalPort", Init=Init.Yes}, + new {Key="server.IsLocal", Type="bool", Name="IsLocal", Init=Init.Yes}, + new {Key="server.ConnectionId", Type="object", Name="ConnectionId", Init=Init.No}, + new {Key="server.ConnectionDisconnect", Type="CancellationToken", Name="ConnectionDisconnect", Init=Init.No}, + +// SSL + new { Key="ssl.ClientCertificate", Type="object", Name="ClientCert", Init=Init.No}, + new { Key="ssl.LoadClientCertAsync", Type="Func", Name="LoadClientCert", Init=Init.No }, + new { Key="ssl.ChannelBinding", Type="ChannelBinding", Name="ChannelBinding", Init=Init.Maybe }, + +// SendFile keys + new {Key="sendfile.SendAsync", Type="Func", Name="SendFileAsync", Init=Init.No}, + +// Opaque keys + new {Key="opaque.Upgrade", Type="OpaqueUpgrade", Name="OpaqueUpgrade", Init=Init.Maybe}, + +// Server specific keys + new { Key="Microsoft.AspNet.Server.WebListener.OwinWebListener", Type="OwinWebListener", Name="Listener", Init=Init.No}, +}.Select((prop, Index)=>new {prop.Key, prop.Type, prop.Name, prop.Init, Index}); + +var lengths = props.OrderBy(prop=>prop.Key.Length).GroupBy(prop=>prop.Key.Length); + +Func IsSet = Index => "((_flag" + (Index / 32) + " & 0x" + (1<<(Index % 32)).ToString("x") + "u) != 0)"; +Func Set = Index => "_flag" + (Index / 32) + " |= 0x" + (1<<(Index % 32)).ToString("x") + "u"; +Func Clear = Index => "_flag" + (Index / 32) + " &= ~0x" + (1<<(Index % 32)).ToString("x") + "u"; + +Func IsInitRequired = Index => "((_initFlag" + (Index / 32) + " & 0x" + (1<<(Index % 32)).ToString("x") + "u) != 0)"; +Func IsInitCompleted = Index => "((_initFlag" + (Index / 32) + " & 0x" + (1<<(Index % 32)).ToString("x") + "u) == 0)"; +Func CompleteInit = Index => "_initFlag" + (Index / 32) + " &= ~0x" + (1<<(Index % 32)).ToString("x") + "u"; + +#> +//----------------------------------------------------------------------- +// +// Copyright (c) Katana Contributors. All rights reserved. +// +//----------------------------------------------------------------------- +// + +using System; +using System.CodeDom.Compiler; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Security.Authentication.ExtendedProtection; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Owin.Host.WebListener +{ + using OpaqueUpgrade = Action, Func, Task>>; + + [GeneratedCode("TextTemplatingFileGenerator", "")] + internal partial class CallEnvironment + { + // Mark all fields with delay initialization support as set. + private UInt32 _flag0 = 0x<#=props.Aggregate(0, (agg,p) => agg | (((p.Init != Init.No) && (p.Index/32==0) ? 1:0)<u; + private UInt32 _flag1 = 0x<#=props.Aggregate(0, (agg,p) => agg | (((p.Init != Init.No) && (p.Index/32==1) ? 1:0)<u; + // Mark all fields with delay initialization support as requiring initialization. + private UInt32 _initFlag0 = 0x<#=props.Aggregate(0, (agg,p) => agg | (((p.Init != Init.No) && (p.Index/32==0) ? 1:0)<u; + private UInt32 _initFlag1 = 0x<#=props.Aggregate(0, (agg,p) => agg | (((p.Init != Init.No) && (p.Index/32==1) ? 1:0)<u; + + internal interface IPropertySource + { +<# foreach(var prop in props) { #> +<# if (prop.Init == Init.Yes) { #> + <#=prop.Type#> Get<#=prop.Name#>(); +<# } #> +<# if (prop.Init == Init.Maybe) { #> + bool TryGet<#=prop.Name#>(ref <#=prop.Type#> value); +<# } #> +<# } #> + } + +<# foreach(var prop in props) { #> + private <#=prop.Type#> _<#=prop.Name#>; +<# } #> + +<# foreach(var prop in props) { #> +<# // call TryGet once if init flag is set, clear value flag if TryGet returns false +if (prop.Init == Init.Maybe) { #> + bool InitProperty<#=prop.Name#>() + { + if (!_propertySource.TryGet<#=prop.Name#>(ref _<#=prop.Name#>)) + { + <#=Clear(prop.Index)#>; + <#=CompleteInit(prop.Index)#>; + return false; + } + <#=CompleteInit(prop.Index)#>; + return true; + } + +<# } #> +<# } #> +<# foreach(var prop in props) { #> + internal <#=prop.Type#> <#=prop.Name#> + { + get + { +<# // call Get once if init flag is set +if (prop.Init == Init.Yes) { #> + if (<#=IsInitRequired(prop.Index)#>) + { + _<#=prop.Name#> = _propertySource.Get<#=prop.Name#>(); + <#=CompleteInit(prop.Index)#>; + } +<# } #> +<# // call TryGet once if init flag is set, clear value flag if TryGet returns false +if (prop.Init == Init.Maybe) { #> + if (<#=IsInitRequired(prop.Index)#>) + { + InitProperty<#=prop.Name#>(); + } +<# } #> + return _<#=prop.Name#>; + } + set + { +<# // clear init flag - the assigned value is definitive +if (prop.Init != Init.No) { #> + <#=CompleteInit(prop.Index)#>; +<# } #> + <#=Set(prop.Index)#>; + _<#=prop.Name#> = value; + } + } + +<# } #> + private bool PropertiesContainsKey(string key) + { + switch (key.Length) + { +<# foreach(var length in lengths) { #> + case <#=length.Key#>: +<# foreach(var prop in length) { #> + if (<#=IsSet(prop.Index)#> && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) + { +<# // variable maybe init might revert +if (prop.Init == Init.Maybe) { #> + if (<#=IsInitCompleted(prop.Index)#> || InitProperty<#=prop.Name#>()) + { + return true; + } +<# } else { #> + return true; +<# } #> + } +<# } #> + break; +<# } #> + } + return false; + } + + private bool PropertiesTryGetValue(string key, out object value) + { + switch (key.Length) + { +<# foreach(var length in lengths) { #> + case <#=length.Key#>: +<# foreach(var prop in length) { #> + if (<#=IsSet(prop.Index)#> && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) + { + value = <#=prop.Name#>; +<# if (prop.Init == Init.Maybe) { #> + // Delayed initialization in the property getter may determine that the element is not actually present + if (!<#=IsSet(prop.Index)#>) + { + value = default(<#=prop.Type#>); + return false; + } +<# } #> + return true; + } +<# } #> + break; +<# } #> + } + value = null; + return false; + } + + private bool PropertiesTrySetValue(string key, object value) + { + switch (key.Length) + { +<# foreach(var length in lengths) { #> + case <#=length.Key#>: +<# foreach(var prop in length) { #> + if (string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) + { + <#=prop.Name#> = (<#=prop.Type#>)value; + return true; + } +<# } #> + break; +<# } #> + } + return false; + } + + private bool PropertiesTryRemove(string key) + { + switch (key.Length) + { +<# foreach(var length in lengths) { #> + case <#=length.Key#>: +<# foreach(var prop in length) { #> + if (<#=IsSet(prop.Index)#> && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) + { +<# if (prop.Init != Init.No) { #> + <#=CompleteInit(prop.Index)#>; +<# } #> + <#=Clear(prop.Index)#>; + _<#=prop.Name#> = default(<#=prop.Type#>); + // This can return true incorrectly for values that delayed initialization may determine are not actually present. + return true; + } +<# } #> + break; +<# } #> + } + return false; + } + + private IEnumerable PropertiesKeys() + { +<# foreach(var prop in props) { #> + if (<#=IsSet(prop.Index)#>) + { +<# if (prop.Init == Init.Maybe) { #> + if (<#=IsInitCompleted(prop.Index)#> || InitProperty<#=prop.Name#>()) + { + yield return "<#=prop.Key#>"; + } +<# } else { #> + yield return "<#=prop.Key#>"; +<# } #> + } +<# } #> + } + + private IEnumerable PropertiesValues() + { +<# foreach(var prop in props) { #> + if (<#=IsSet(prop.Index)#>) + { +<# if (prop.Init == Init.Maybe) { #> + if (<#=IsInitCompleted(prop.Index)#> || InitProperty<#=prop.Name#>()) + { + yield return <#=prop.Name#>; + } +<# } else { #> + yield return <#=prop.Name#>; +<# } #> + } +<# } #> + } + + private IEnumerable> PropertiesEnumerable() + { +<# foreach(var prop in props) { #> + if (<#=IsSet(prop.Index)#>) + { +<# if (prop.Init == Init.Maybe) { #> + if (<#=IsInitCompleted(prop.Index)#> || InitProperty<#=prop.Name#>()) + { + yield return new KeyValuePair("<#=prop.Key#>", <#=prop.Name#>); + } +<# } else { #> + yield return new KeyValuePair("<#=prop.Key#>", <#=prop.Name#>); +<# } #> + } +<# } #> + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.cs new file mode 100644 index 0000000000..360a2ea245 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.cs @@ -0,0 +1,165 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- +// Copyright 2011-2012 Katana contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal partial class CallEnvironment : IDictionary + { + private static readonly IDictionary WeakNilEnvironment = new NilEnvDictionary(); + + private readonly IPropertySource _propertySource; + private IDictionary _extra = WeakNilEnvironment; + + internal CallEnvironment(IPropertySource propertySource) + { + _propertySource = propertySource; + } + + private IDictionary Extra + { + get { return _extra; } + } + + private IDictionary StrongExtra + { + get + { + if (_extra == WeakNilEnvironment) + { + Interlocked.CompareExchange(ref _extra, new Dictionary(), WeakNilEnvironment); + } + return _extra; + } + } + + internal bool IsExtraDictionaryCreated + { + get { return _extra != WeakNilEnvironment; } + } + + public object this[string key] + { + get + { + object value; + return PropertiesTryGetValue(key, out value) ? value : Extra[key]; + } + set + { + if (!PropertiesTrySetValue(key, value)) + { + StrongExtra[key] = value; + } + } + } + + public void Add(string key, object value) + { + if (!PropertiesTrySetValue(key, value)) + { + StrongExtra.Add(key, value); + } + } + + public bool ContainsKey(string key) + { + return PropertiesContainsKey(key) || Extra.ContainsKey(key); + } + + public ICollection Keys + { + get { return PropertiesKeys().Concat(Extra.Keys).ToArray(); } + } + + public bool Remove(string key) + { + // Although this is a mutating operation, Extra is used instead of StrongExtra, + // because if a real dictionary has not been allocated the default behavior of the + // nil dictionary is perfectly fine. + return PropertiesTryRemove(key) || Extra.Remove(key); + } + + public bool TryGetValue(string key, out object value) + { + return PropertiesTryGetValue(key, out value) || Extra.TryGetValue(key, out value); + } + + public ICollection Values + { + get { return PropertiesValues().Concat(Extra.Values).ToArray(); } + } + + public void Add(KeyValuePair item) + { + ((IDictionary)this).Add(item.Key, item.Value); + } + + public void Clear() + { + foreach (var key in PropertiesKeys()) + { + PropertiesTryRemove(key); + } + Extra.Clear(); + } + + public bool Contains(KeyValuePair item) + { + object value; + return ((IDictionary)this).TryGetValue(item.Key, out value) && Object.Equals(value, item.Value); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + PropertiesEnumerable().Concat(Extra).ToArray().CopyTo(array, arrayIndex); + } + + public int Count + { + get { return PropertiesKeys().Count() + Extra.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public bool Remove(KeyValuePair item) + { + return ((IDictionary)this).Contains(item) && + ((IDictionary)this).Remove(item.Key); + } + + public IEnumerator> GetEnumerator() + { + return PropertiesEnumerable().Concat(Extra).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IDictionary)this).GetEnumerator(); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs new file mode 100644 index 0000000000..3cd17db788 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs @@ -0,0 +1,347 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +#if NET45 + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + // This class is used to load the client certificate on-demand. Because client certs are optional, all + // failures are handled internally and reported via ClientCertException or ClientCertError. + internal unsafe sealed class ClientCertLoader : IAsyncResult, IDisposable + { + private const uint CertBoblSize = 1500; + private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(WaitCallback); + + private SafeNativeOverlapped _overlapped; + private byte[] _backingBuffer; + private UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* _memoryBlob; + private uint _size; + private TaskCompletionSource _tcs; + private RequestContext _requestContext; + + private int _clientCertError; + private X509Certificate2 _clientCert; + private Exception _clientCertException; + + internal ClientCertLoader(RequestContext requestContext) + { + _requestContext = requestContext; + _tcs = new TaskCompletionSource(); + // we will use this overlapped structure to issue async IO to ul + // the event handle will be put in by the BeginHttpApi2.ERROR_SUCCESS() method + Reset(CertBoblSize); + } + + internal X509Certificate2 ClientCert + { + get + { + Contract.Assert(Task.IsCompleted); + return _clientCert; + } + } + + internal int ClientCertError + { + get + { + Contract.Assert(Task.IsCompleted); + return _clientCertError; + } + } + + internal Exception ClientCertException + { + get + { + Contract.Assert(Task.IsCompleted); + return _clientCertException; + } + } + + private RequestContext RequestContext + { + get + { + return _requestContext; + } + } + + private Task Task + { + get + { + return _tcs.Task; + } + } + + private SafeNativeOverlapped NativeOverlapped + { + get + { + return _overlapped; + } + } + + private UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* RequestBlob + { + get + { + return _memoryBlob; + } + } + + private void Reset(uint size) + { + if (size == _size) + { + return; + } + if (_size != 0) + { + _overlapped.Dispose(); + } + _size = size; + if (size == 0) + { + _overlapped = null; + _memoryBlob = null; + _backingBuffer = null; + return; + } + _backingBuffer = new byte[checked((int)size)]; + Overlapped overlapped = new Overlapped(); + overlapped.AsyncResult = this; + _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, _backingBuffer)); + _memoryBlob = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); + } + + // When you use netsh to configure HTTP.SYS with clientcertnegotiation = enable + // which means negotiate client certificates, when the client makes the + // initial SSL connection, the server (HTTP.SYS) requests the client certificate. + // + // Some apps may not want to negotiate the client cert at the beginning, + // perhaps serving the default.htm. In this case the HTTP.SYS is configured + // with clientcertnegotiation = disabled, which means that the client certificate is + // optional so initially when SSL is established HTTP.SYS won't ask for client + // certificate. This works fine for the default.htm in the case above, + // however, if the app wants to demand a client certificate at a later time + // perhaps showing "YOUR ORDERS" page, then the server wants to negotiate + // Client certs. This will in turn makes HTTP.SYS to do the + // SEC_I_RENOGOTIATE through which the client cert demand is made + // + // NOTE: When calling HttpReceiveClientCertificate you can get + // ERROR_NOT_FOUND - which means the client did not provide the cert + // If this is important, the server should respond with 403 forbidden + // HTTP.SYS will not do this for you automatically + internal Task LoadClientCertificateAsync() + { + uint size = CertBoblSize; + bool retry; + do + { + retry = false; + uint bytesReceived = 0; + + uint statusCode = + UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( + RequestContext.RequestQueueHandle, + RequestContext.Request.ConnectionId, + (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, + RequestBlob, + size, + &bytesReceived, + NativeOverlapped); + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) + { + UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = RequestBlob; + size = bytesReceived + pClientCertInfo->CertEncodedSize; + Reset(size); + retry = true; + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) + { + // The client did not send a cert. + Complete(0, null); + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + OwinWebListener.SkipIOCPCallbackOnSuccess) + { + IOCompleted(statusCode, bytesReceived); + } + else if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + // Some other bad error, possible(?) return values are: + // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED + // Also ERROR_BAD_DATA if we got it twice or it reported smaller size buffer required. + Fail(new WebListenerException((int)statusCode)); + } + } + while (retry); + + return Task; + } + + private void Complete(int certErrors, X509Certificate2 cert) + { + // May be null + _clientCert = cert; + _clientCertError = certErrors; + _tcs.TrySetResult(null); + Dispose(); + } + + private void Fail(Exception ex) + { + // TODO: Log + _clientCertException = ex; + _tcs.TrySetResult(null); + } + + private unsafe void IOCompleted(uint errorCode, uint numBytes) + { + IOCompleted(this, errorCode, numBytes); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirected to callback")] + private static unsafe void IOCompleted(ClientCertLoader asyncResult, uint errorCode, uint numBytes) + { + RequestContext requestContext = asyncResult.RequestContext; + try + { + if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) + { + // There is a bug that has existed in http.sys since w2k3. Bytesreceived will only + // return the size of the initial cert structure. To get the full size, + // we need to add the certificate encoding size as well. + + UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob; + asyncResult.Reset(numBytes + pClientCertInfo->CertEncodedSize); + + uint bytesReceived = 0; + errorCode = + UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( + requestContext.RequestQueueHandle, + requestContext.Request.ConnectionId, + (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, + asyncResult._memoryBlob, + asyncResult._size, + &bytesReceived, + asyncResult._overlapped); + + if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING || + (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && !OwinWebListener.SkipIOCPCallbackOnSuccess)) + { + return; + } + } + + if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) + { + // The client did not send a cert. + asyncResult.Complete(0, null); + } + else if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + asyncResult.Fail(new WebListenerException((int)errorCode)); + } + else + { + UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult._memoryBlob; + if (pClientCertInfo == null) + { + asyncResult.Complete(0, null); + } + else + { + if (pClientCertInfo->pCertEncoded != null) + { + try + { + byte[] certEncoded = new byte[pClientCertInfo->CertEncodedSize]; + Marshal.Copy((IntPtr)pClientCertInfo->pCertEncoded, certEncoded, 0, certEncoded.Length); + asyncResult.Complete((int)pClientCertInfo->CertFlags, new X509Certificate2(certEncoded)); + } + catch (CryptographicException exception) + { + // TODO: Log + asyncResult.Fail(exception); + } + catch (SecurityException exception) + { + // TODO: Log + asyncResult.Fail(exception); + } + } + } + } + } + catch (Exception exception) + { + asyncResult.Fail(exception); + } + } + + private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) + { + Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); + ClientCertLoader asyncResult = (ClientCertLoader)callbackOverlapped.AsyncResult; + + IOCompleted(asyncResult, errorCode, numBytes); + } + + public void Dispose() + { + Dispose(true); + } + + private void Dispose(bool disposing) + { + if (disposing) + { + if (_overlapped != null) + { + _memoryBlob = null; + _overlapped.Dispose(); + } + } + } + + public object AsyncState + { + get { return _tcs.Task.AsyncState; } + } + + public WaitHandle AsyncWaitHandle + { + get { return ((IAsyncResult)_tcs.Task).AsyncWaitHandle; } + } + + public bool CompletedSynchronously + { + get { return ((IAsyncResult)_tcs.Task).CompletedSynchronously; } + } + + public bool IsCompleted + { + get { return _tcs.Task.IsCompleted; } + } + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs new file mode 100644 index 0000000000..f6861f9bd6 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs @@ -0,0 +1,17 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.Server.WebListener +{ + internal enum EntitySendFormat + { + ContentLength = 0, // Content-Length: XXX + Chunked = 1, // Transfer-Encoding: chunked + /* + Raw = 2, // the app is responsible for sending the correct headers and body encoding + */ + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HeaderEncoding.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HeaderEncoding.cs new file mode 100644 index 0000000000..24a8df80ff --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HeaderEncoding.cs @@ -0,0 +1,97 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.AspNet.Server.WebListener +{ + // we use this static class as a helper class to encode/decode HTTP headers. + // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF + // and a byte in the range 0x00-0xFF (which is the range that can hit the network). + // The Latin-1 encoding (ISO-88591-1) (GetEncoding(28591)) works for byte[] to string, but is a little slow. + // It doesn't work for string -> byte[] because of best-fit-mapping problems. + internal static class HeaderEncoding + { + internal static unsafe string GetString(byte[] bytes, int byteIndex, int byteCount) + { + fixed (byte* pBytes = bytes) + return GetString(pBytes + byteIndex, byteCount); + } + + internal static unsafe string GetString(sbyte* pBytes, int byteCount) + { + return GetString((byte*)pBytes, byteCount); + } + + internal static unsafe string GetString(byte* pBytes, int byteCount) + { + if (byteCount < 1) + { + return string.Empty; + } + + string s = new String('\0', byteCount); + + fixed (char* pStr = s) + { + char* pString = pStr; + while (byteCount >= 8) + { + pString[0] = (char)pBytes[0]; + pString[1] = (char)pBytes[1]; + pString[2] = (char)pBytes[2]; + pString[3] = (char)pBytes[3]; + pString[4] = (char)pBytes[4]; + pString[5] = (char)pBytes[5]; + pString[6] = (char)pBytes[6]; + pString[7] = (char)pBytes[7]; + pString += 8; + pBytes += 8; + byteCount -= 8; + } + for (int i = 0; i < byteCount; i++) + { + pString[i] = (char)pBytes[i]; + } + } + + return s; + } + + internal static int GetByteCount(string myString) + { + return myString.Length; + } + internal static unsafe void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex) + { + if (myString.Length == 0) + { + return; + } + fixed (byte* bufferPointer = bytes) + { + byte* newBufferPointer = bufferPointer + byteIndex; + int finalIndex = charIndex + charCount; + while (charIndex < finalIndex) + { + *newBufferPointer++ = (byte)myString[charIndex++]; + } + } + } + internal static unsafe byte[] GetBytes(string myString) + { + byte[] bytes = new byte[myString.Length]; + if (myString.Length != 0) + { + GetBytes(myString, 0, myString.Length, bytes, 0); + } + return bytes; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpKnownHeaderNames.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpKnownHeaderNames.cs new file mode 100644 index 0000000000..9885de2fcd --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpKnownHeaderNames.cs @@ -0,0 +1,75 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class HttpKnownHeaderNames + { + internal const string CacheControl = "Cache-Control"; + internal const string Connection = "Connection"; + internal const string Date = "Date"; + internal const string KeepAlive = "Keep-Alive"; + internal const string Pragma = "Pragma"; + internal const string ProxyConnection = "Proxy-Connection"; + internal const string Trailer = "Trailer"; + internal const string TransferEncoding = "Transfer-Encoding"; + internal const string Upgrade = "Upgrade"; + internal const string Via = "Via"; + internal const string Warning = "Warning"; + internal const string ContentLength = "Content-Length"; + internal const string ContentType = "Content-Type"; + internal const string ContentDisposition = "Content-Disposition"; + internal const string ContentEncoding = "Content-Encoding"; + internal const string ContentLanguage = "Content-Language"; + internal const string ContentLocation = "Content-Location"; + internal const string ContentRange = "Content-Range"; + internal const string Expires = "Expires"; + internal const string LastModified = "Last-Modified"; + internal const string Age = "Age"; + internal const string Location = "Location"; + internal const string ProxyAuthenticate = "Proxy-Authenticate"; + internal const string RetryAfter = "Retry-After"; + internal const string Server = "Server"; + internal const string SetCookie = "Set-Cookie"; + internal const string SetCookie2 = "Set-Cookie2"; + internal const string Vary = "Vary"; + internal const string WWWAuthenticate = "WWW-Authenticate"; + internal const string Accept = "Accept"; + internal const string AcceptCharset = "Accept-Charset"; + internal const string AcceptEncoding = "Accept-Encoding"; + internal const string AcceptLanguage = "Accept-Language"; + internal const string Authorization = "Authorization"; + internal const string Cookie = "Cookie"; + internal const string Cookie2 = "Cookie2"; + internal const string Expect = "Expect"; + internal const string From = "From"; + internal const string Host = "Host"; + internal const string IfMatch = "If-Match"; + internal const string IfModifiedSince = "If-Modified-Since"; + internal const string IfNoneMatch = "If-None-Match"; + internal const string IfRange = "If-Range"; + internal const string IfUnmodifiedSince = "If-Unmodified-Since"; + internal const string MaxForwards = "Max-Forwards"; + internal const string ProxyAuthorization = "Proxy-Authorization"; + internal const string Referer = "Referer"; + internal const string Range = "Range"; + internal const string UserAgent = "User-Agent"; + internal const string ContentMD5 = "Content-MD5"; + internal const string ETag = "ETag"; + internal const string TE = "TE"; + internal const string Allow = "Allow"; + internal const string AcceptRanges = "Accept-Ranges"; + internal const string P3P = "P3P"; + internal const string XPoweredBy = "X-Powered-By"; + internal const string XAspNetVersion = "X-AspNet-Version"; + internal const string SecWebSocketKey = "Sec-WebSocket-Key"; + internal const string SecWebSocketExtensions = "Sec-WebSocket-Extensions"; + internal const string SecWebSocketAccept = "Sec-WebSocket-Accept"; + internal const string Origin = "Origin"; + internal const string SecWebSocketProtocol = "Sec-WebSocket-Protocol"; + internal const string SecWebSocketVersion = "Sec-WebSocket-Version"; + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpReasonPhrase.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpReasonPhrase.cs new file mode 100644 index 0000000000..27370832ff --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpReasonPhrase.cs @@ -0,0 +1,109 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class HttpReasonPhrase + { + private static readonly string[][] HttpReasonPhrases = new string[][] + { + null, + + new string[] + { + /* 100 */ "Continue", + /* 101 */ "Switching Protocols", + /* 102 */ "Processing" + }, + + new string[] + { + /* 200 */ "OK", + /* 201 */ "Created", + /* 202 */ "Accepted", + /* 203 */ "Non-Authoritative Information", + /* 204 */ "No Content", + /* 205 */ "Reset Content", + /* 206 */ "Partial Content", + /* 207 */ "Multi-Status" + }, + + new string[] + { + /* 300 */ "Multiple Choices", + /* 301 */ "Moved Permanently", + /* 302 */ "Found", + /* 303 */ "See Other", + /* 304 */ "Not Modified", + /* 305 */ "Use Proxy", + /* 306 */ null, + /* 307 */ "Temporary Redirect" + }, + + new string[] + { + /* 400 */ "Bad Request", + /* 401 */ "Unauthorized", + /* 402 */ "Payment Required", + /* 403 */ "Forbidden", + /* 404 */ "Not Found", + /* 405 */ "Method Not Allowed", + /* 406 */ "Not Acceptable", + /* 407 */ "Proxy Authentication Required", + /* 408 */ "Request Timeout", + /* 409 */ "Conflict", + /* 410 */ "Gone", + /* 411 */ "Length Required", + /* 412 */ "Precondition Failed", + /* 413 */ "Request Entity Too Large", + /* 414 */ "Request-Uri Too Long", + /* 415 */ "Unsupported Media Type", + /* 416 */ "Requested Range Not Satisfiable", + /* 417 */ "Expectation Failed", + /* 418 */ null, + /* 419 */ null, + /* 420 */ null, + /* 421 */ null, + /* 422 */ "Unprocessable Entity", + /* 423 */ "Locked", + /* 424 */ "Failed Dependency", + /* 425 */ null, + /* 426 */ "Upgrade Required", // RFC 2817 + }, + + new string[] + { + /* 500 */ "Internal Server Error", + /* 501 */ "Not Implemented", + /* 502 */ "Bad Gateway", + /* 503 */ "Service Unavailable", + /* 504 */ "Gateway Timeout", + /* 505 */ "Http Version Not Supported", + /* 506 */ null, + /* 507 */ "Insufficient Storage" + } + }; + + internal static string Get(HttpStatusCode code) + { + return Get((int)code); + } + + internal static string Get(int code) + { + if (code >= 100 && code < 600) + { + int i = code / 100; + int j = code % 100; + if (j < HttpReasonPhrases[i].Length) + { + return HttpReasonPhrases[i][j]; + } + } + return null; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpStatusCode.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpStatusCode.cs new file mode 100644 index 0000000000..88e6fe4b18 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpStatusCode.cs @@ -0,0 +1,314 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.Server.WebListener +{ + // Redirect Status code numbers that need to be defined. + + /// + /// Contains the values of status + /// codes defined for the HTTP protocol. + /// + // UEUE : Any int can be cast to a HttpStatusCode to allow checking for non http1.1 codes. + internal enum HttpStatusCode + { + // Informational 1xx + + /// + /// [To be supplied.] + /// + Continue = 100, + + /// + /// [To be supplied.] + /// + SwitchingProtocols = 101, + + // Successful 2xx + + /// + /// [To be supplied.] + /// + OK = 200, + + /// + /// [To be supplied.] + /// + Created = 201, + + /// + /// [To be supplied.] + /// + Accepted = 202, + + /// + /// [To be supplied.] + /// + NonAuthoritativeInformation = 203, + + /// + /// [To be supplied.] + /// + NoContent = 204, + + /// + /// [To be supplied.] + /// + ResetContent = 205, + + /// + /// [To be supplied.] + /// + PartialContent = 206, + + // Redirection 3xx + + /// + /// [To be supplied.] + /// + MultipleChoices = 300, + + /// + /// [To be supplied.] + /// + Ambiguous = 300, + + /// + /// [To be supplied.] + /// + MovedPermanently = 301, + + /// + /// [To be supplied.] + /// + Moved = 301, + + /// + /// [To be supplied.] + /// + Found = 302, + + /// + /// [To be supplied.] + /// + Redirect = 302, + + /// + /// [To be supplied.] + /// + SeeOther = 303, + + /// + /// [To be supplied.] + /// + RedirectMethod = 303, + + /// + /// [To be supplied.] + /// + NotModified = 304, + + /// + /// [To be supplied.] + /// + UseProxy = 305, + + /// + /// [To be supplied.] + /// + Unused = 306, + + /// + /// [To be supplied.] + /// + TemporaryRedirect = 307, + + /// + /// [To be supplied.] + /// + RedirectKeepVerb = 307, + + // Client Error 4xx + + /// + /// [To be supplied.] + /// + BadRequest = 400, + + /// + /// [To be supplied.] + /// + Unauthorized = 401, + + /// + /// [To be supplied.] + /// + PaymentRequired = 402, + + /// + /// [To be supplied.] + /// + Forbidden = 403, + + /// + /// [To be supplied.] + /// + NotFound = 404, + + /// + /// [To be supplied.] + /// + MethodNotAllowed = 405, + + /// + /// [To be supplied.] + /// + NotAcceptable = 406, + + /// + /// [To be supplied.] + /// + ProxyAuthenticationRequired = 407, + + /// + /// [To be supplied.] + /// + RequestTimeout = 408, + + /// + /// [To be supplied.] + /// + Conflict = 409, + + /// + /// [To be supplied.] + /// + Gone = 410, + + /// + /// [To be supplied.] + /// + LengthRequired = 411, + + /// + /// [To be supplied.] + /// + PreconditionFailed = 412, + + /// + /// [To be supplied.] + /// + RequestEntityTooLarge = 413, + + /// + /// [To be supplied.] + /// + RequestUriTooLong = 414, + + /// + /// [To be supplied.] + /// + UnsupportedMediaType = 415, + + /// + /// [To be supplied.] + /// + RequestedRangeNotSatisfiable = 416, + + /// + /// [To be supplied.] + /// + ExpectationFailed = 417, + + UpgradeRequired = 426, + + // Server Error 5xx + + /// + /// [To be supplied.] + /// + InternalServerError = 500, + + /// + /// [To be supplied.] + /// + NotImplemented = 501, + + /// + /// [To be supplied.] + /// + BadGateway = 502, + + /// + /// [To be supplied.] + /// + ServiceUnavailable = 503, + + /// + /// [To be supplied.] + /// + GatewayTimeout = 504, + + /// + /// [To be supplied.] + /// + HttpVersionNotSupported = 505, + } // enum HttpStatusCode + + /* + Fielding, et al. Standards Track [Page 3] + + RFC 2616 HTTP/1.1 June 1999 + + + 10.1 Informational 1xx ...........................................57 + 10.1.1 100 Continue .............................................58 + 10.1.2 101 Switching Protocols ..................................58 + 10.2 Successful 2xx ..............................................58 + 10.2.1 200 OK ...................................................58 + 10.2.2 201 Created ..............................................59 + 10.2.3 202 Accepted .............................................59 + 10.2.4 203 Non-Authoritative Information ........................59 + 10.2.5 204 No Content ...........................................60 + 10.2.6 205 Reset Content ........................................60 + 10.2.7 206 Partial Content ......................................60 + 10.3 Redirection 3xx .............................................61 + 10.3.1 300 Multiple Choices .....................................61 + 10.3.2 301 Moved Permanently ....................................62 + 10.3.3 302 Found ................................................62 + 10.3.4 303 See Other ............................................63 + 10.3.5 304 Not Modified .........................................63 + 10.3.6 305 Use Proxy ............................................64 + 10.3.7 306 (Unused) .............................................64 + 10.3.8 307 Temporary Redirect ...................................65 + 10.4 Client Error 4xx ............................................65 + 10.4.1 400 Bad Request .........................................65 + 10.4.2 401 Unauthorized ........................................66 + 10.4.3 402 Payment Required ....................................66 + 10.4.4 403 Forbidden ...........................................66 + 10.4.5 404 Not Found ...........................................66 + 10.4.6 405 Method Not Allowed ..................................66 + 10.4.7 406 Not Acceptable ......................................67 + 10.4.8 407 Proxy Authentication Required .......................67 + 10.4.9 408 Request Timeout .....................................67 + 10.4.10 409 Conflict ............................................67 + 10.4.11 410 Gone ................................................68 + 10.4.12 411 Length Required .....................................68 + 10.4.13 412 Precondition Failed .................................68 + 10.4.14 413 Request Entity Too Large ............................69 + 10.4.15 414 Request-URI Too Long ................................69 + 10.4.16 415 Unsupported Media Type ..............................69 + 10.4.17 416 Requested Range Not Satisfiable .....................69 + 10.4.18 417 Expectation Failed ..................................70 + 10.5 Server Error 5xx ............................................70 + 10.5.1 500 Internal Server Error ................................70 + 10.5.2 501 Not Implemented ......................................70 + 10.5.3 502 Bad Gateway ..........................................70 + 10.5.4 503 Service Unavailable ..................................70 + 10.5.5 504 Gateway Timeout ......................................71 + 10.5.6 505 HTTP Version Not Supported ...........................71 + */ +} // namespace System.Net diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NativeRequestContext.cs new file mode 100644 index 0000000000..8ab4f029cb --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NativeRequestContext.cs @@ -0,0 +1,170 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal unsafe class NativeRequestContext : IDisposable + { + private const int DefaultBufferSize = 4096; + private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* _memoryBlob; + private IntPtr _originalBlobAddress; + private byte[] _backingBuffer; + private SafeNativeOverlapped _nativeOverlapped; + private AsyncAcceptContext _acceptResult; + + internal NativeRequestContext(AsyncAcceptContext result) + { + _acceptResult = result; + UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* requestBlob = Allocate(0); + if (requestBlob == null) + { + GC.SuppressFinalize(this); + } + else + { + _memoryBlob = requestBlob; + } + } + + internal SafeNativeOverlapped NativeOverlapped + { + get + { + return _nativeOverlapped; + } + } + + internal UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* RequestBlob + { + get + { + Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestBlob requested after ReleasePins()."); + return _memoryBlob; + } + } + + internal byte[] RequestBuffer + { + get + { + return _backingBuffer; + } + } + + internal uint Size + { + get + { + return (uint)_backingBuffer.Length; + } + } + + internal IntPtr OriginalBlobAddress + { + get + { + UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* blob = _memoryBlob; + return (blob == null ? _originalBlobAddress : (IntPtr)blob); + } + } + + // ReleasePins() should be called exactly once. It must be called before Dispose() is called, which means it must be called + // before an object (Request) which closes the RequestContext on demand is returned to the application. + internal void ReleasePins() + { + Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice."); + _originalBlobAddress = (IntPtr)_memoryBlob; + UnsetBlob(); + OnReleasePins(); + } + + private void OnReleasePins() + { + if (_nativeOverlapped != null) + { + SafeNativeOverlapped nativeOverlapped = _nativeOverlapped; + _nativeOverlapped = null; + nativeOverlapped.Dispose(); + } + } + + public void Dispose() + { + Debug.Assert(_memoryBlob == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins()."); + Dispose(true); + } + + protected void Dispose(bool disposing) + { + if (_nativeOverlapped != null) + { + Debug.Assert(!disposing, "AsyncRequestContext::Dispose()|Must call ReleasePins() before calling Dispose()."); + _nativeOverlapped.Dispose(); + } + } + + private void SetBlob(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* requestBlob) + { + Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::Dispose()|SetBlob() called after ReleasePins()."); + if (requestBlob == null) + { + UnsetBlob(); + return; + } + + if (_memoryBlob == null) + { + GC.ReRegisterForFinalize(this); + } + _memoryBlob = requestBlob; + } + + private void UnsetBlob() + { + if (_memoryBlob != null) + { + GC.SuppressFinalize(this); + } + _memoryBlob = null; + } + + private void SetBuffer(int size) + { + _backingBuffer = size == 0 ? null : new byte[size]; + } + + private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size) + { + uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size; + if (_nativeOverlapped != null && newSize != RequestBuffer.Length) + { + SafeNativeOverlapped nativeOverlapped = _nativeOverlapped; + _nativeOverlapped = null; + nativeOverlapped.Dispose(); + } + if (_nativeOverlapped == null) + { + SetBuffer(checked((int)newSize)); + Overlapped overlapped = new Overlapped(); + overlapped.AsyncResult = _acceptResult; + _nativeOverlapped = new SafeNativeOverlapped(overlapped.Pack(AsyncAcceptContext.IOCallback, RequestBuffer)); + return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); + } + return RequestBlob; + } + + internal void Reset(ulong requestId, uint size) + { + SetBlob(Allocate(size)); + RequestBlob->RequestId = requestId; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NilEnvDictionary.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NilEnvDictionary.cs new file mode 100644 index 0000000000..af6cc6aff5 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NilEnvDictionary.cs @@ -0,0 +1,115 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- +// Copyright 2011-2012 Katana contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class NilEnvDictionary : IDictionary + { + private static readonly string[] EmptyKeys = new string[0]; + private static readonly object[] EmptyValues = new object[0]; + private static readonly IEnumerable> EmptyKeyValuePairs = Enumerable.Empty>(); + + public int Count + { + get { return 0; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public ICollection Keys + { + get { return EmptyKeys; } + } + + public ICollection Values + { + get { return EmptyValues; } + } + + [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "Not Implemented")] + public object this[string key] + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public IEnumerator> GetEnumerator() + { + return EmptyKeyValuePairs.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return EmptyKeyValuePairs.GetEnumerator(); + } + + public void Add(KeyValuePair item) + { + throw new NotImplementedException(); + } + + public void Clear() + { + } + + public bool Contains(KeyValuePair item) + { + return false; + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + } + + public bool Remove(KeyValuePair item) + { + return false; + } + + public bool ContainsKey(string key) + { + return false; + } + + public void Add(string key, object value) + { + throw new NotImplementedException(); + } + + public bool Remove(string key) + { + return false; + } + + public bool TryGetValue(string key, out object value) + { + value = null; + return false; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/OpaqueStream.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/OpaqueStream.cs new file mode 100644 index 0000000000..6238d9185d --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/OpaqueStream.cs @@ -0,0 +1,168 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + // A duplex wrapper around RequestStream and ResponseStream. + // TODO: Consider merging RequestStream and ResponseStream instead. + internal class OpaqueStream : Stream + { + private readonly Stream _requestStream; + private readonly Stream _responseStream; + + internal OpaqueStream(Stream requestStream, Stream responseStream) + { + _requestStream = requestStream; + _responseStream = responseStream; + } + +#region Properties + + public override bool CanRead + { + get { return _requestStream.CanRead; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanTimeout + { + get { return _requestStream.CanTimeout || _responseStream.CanTimeout; } + } + + public override bool CanWrite + { + get { return _responseStream.CanWrite; } + } + + public override long Length + { + get { throw new NotSupportedException(Resources.Exception_NoSeek); } + } + + public override long Position + { + get { throw new NotSupportedException(Resources.Exception_NoSeek); } + set { throw new NotSupportedException(Resources.Exception_NoSeek); } + } + + public override int ReadTimeout + { + get { return _requestStream.ReadTimeout; } + set { _requestStream.ReadTimeout = value; } + } + + public override int WriteTimeout + { + get { return _responseStream.WriteTimeout; } + set { _responseStream.WriteTimeout = value; } + } + +#endregion Properties + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + +#region Read + + public override int Read(byte[] buffer, int offset, int count) + { + return _requestStream.Read(buffer, offset, count); + } + + public override int ReadByte() + { + return _requestStream.ReadByte(); + } +#if NET45 + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return _requestStream.BeginRead(buffer, offset, count, callback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + return _requestStream.EndRead(asyncResult); + } +#endif + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return _requestStream.ReadAsync(buffer, offset, count, cancellationToken); + } + + public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) + { + return _requestStream.CopyToAsync(destination, bufferSize, cancellationToken); + } + +#endregion Read + +#region Write + + public override void Write(byte[] buffer, int offset, int count) + { + _responseStream.Write(buffer, offset, count); + } + + public override void WriteByte(byte value) + { + _responseStream.WriteByte(value); + } +#if NET45 + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return _responseStream.BeginWrite(buffer, offset, count, callback, state); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + _responseStream.EndWrite(asyncResult); + } +#endif + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return _responseStream.WriteAsync(buffer, offset, count, cancellationToken); + } + + public override void Flush() + { + _responseStream.Flush(); + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + return _responseStream.FlushAsync(cancellationToken); + } + +#endregion Write + + protected override void Dispose(bool disposing) + { + // TODO: Suppress dispose? + if (disposing) + { + _requestStream.Dispose(); + _responseStream.Dispose(); + } + base.Dispose(disposing); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs new file mode 100644 index 0000000000..86b25185fb --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -0,0 +1,456 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Net; +using System.Runtime.InteropServices; +using System.Security.Authentication.ExtendedProtection; +using System.Security.Principal; +using System.Text; +using System.Threading; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal sealed unsafe class Request : IDisposable + { + private RequestContext _requestContext; + private NativeRequestContext _nativeRequestContext; + + private ulong _requestId; + private ulong _connectionId; + private ulong _contextId; + + private SslStatus _sslStatus; + + private string _httpMethod; + private Version _httpVersion; + + private Uri _requestUri; + private string _rawUrl; + private string _cookedUrlHost; + private string _cookedUrlPath; + private string _cookedUrlQuery; + + private RequestHeaders _headers; + private BoundaryType _contentBoundaryType; + private long _contentLength; + private Stream _requestStream; + private SocketAddress _localEndPoint; + private SocketAddress _remoteEndPoint; + + private IPrincipal _user; + + private bool _isDisposed = false; + private CancellationTokenRegistration _disconnectRegistration; + + internal Request(RequestContext httpContext, NativeRequestContext memoryBlob) + { + // TODO: Verbose log + _requestContext = httpContext; + _nativeRequestContext = memoryBlob; + _contentBoundaryType = BoundaryType.None; + + // Set up some of these now to avoid refcounting on memory blob later. + _requestId = memoryBlob.RequestBlob->RequestId; + _connectionId = memoryBlob.RequestBlob->ConnectionId; + _contextId = memoryBlob.RequestBlob->UrlContext; + _sslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure : + memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : + SslStatus.ClientCert; + if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0) + { + _rawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); + } + + UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl; + if (cookedUrl.pHost != null && cookedUrl.HostLength > 0) + { + _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2); + } + if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0) + { + _cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); + } + if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0) + { + _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); + } + + int major = memoryBlob.RequestBlob->Version.MajorVersion; + int minor = memoryBlob.RequestBlob->Version.MinorVersion; + if (major == 1 && minor == 1) + { + _httpVersion = Constants.V1_1; + } + else if (major == 1 && minor == 0) + { + _httpVersion = Constants.V1_0; + } + else + { + _httpVersion = new Version(major, minor); + } + + _httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, OriginalBlobAddress); + _headers = new RequestHeaders(_nativeRequestContext); + + UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2* requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; + _user = GetUser(requestV2->pRequestInfo); + + // TODO: Verbose log parameters + + // TODO: Verbose log headers + } + + internal SslStatus SslStatus + { + get + { + return _sslStatus; + } + } + + internal ulong ConnectionId + { + get + { + return _connectionId; + } + } + + internal ulong ContextId + { + get { return _contextId; } + } + + internal RequestContext RequestContext + { + get + { + return _requestContext; + } + } + + internal byte[] RequestBuffer + { + get + { + CheckDisposed(); + return _nativeRequestContext.RequestBuffer; + } + } + + internal IntPtr OriginalBlobAddress + { + get + { + CheckDisposed(); + return _nativeRequestContext.OriginalBlobAddress; + } + } + + // Without the leading ? + internal string Query + { + get + { + if (!string.IsNullOrWhiteSpace(_cookedUrlQuery)) + { + return _cookedUrlQuery.Substring(1); + } + return string.Empty; + } + } + + internal ulong RequestId + { + get + { + return _requestId; + } + } + + // TODO: Move this to the constructor, that's where it will be called. + internal long ContentLength64 + { + get + { + if (_contentBoundaryType == BoundaryType.None) + { + string transferEncoding = Headers.Get(HttpKnownHeaderNames.TransferEncoding) ?? string.Empty; + if ("chunked".Equals(transferEncoding.Trim(), StringComparison.OrdinalIgnoreCase)) + { + _contentBoundaryType = BoundaryType.Chunked; + _contentLength = -1; + } + else + { + _contentLength = 0; + _contentBoundaryType = BoundaryType.ContentLength; + string length = Headers.Get(HttpKnownHeaderNames.ContentLength) ?? string.Empty; + if (length != null) + { + if (!long.TryParse(length.Trim(), NumberStyles.None, + CultureInfo.InvariantCulture.NumberFormat, out _contentLength)) + { + _contentLength = 0; + _contentBoundaryType = BoundaryType.Invalid; + } + } + } + } + + return _contentLength; + } + } + + internal IDictionary Headers + { + get + { + return _headers; + } + } + + internal string HttpMethod + { + get + { + return _httpMethod; + } + } + + internal Stream InputStream + { + get + { + if (_requestStream == null) + { + // TODO: Move this to the constructor (or a lazy Env dictionary) + _requestStream = HasEntityBody ? new RequestStream(RequestContext) : Stream.Null; + } + return _requestStream; + } + } + + internal bool IsLocal + { + get + { + return LocalEndPoint.GetIPAddressString().Equals(RemoteEndPoint.GetIPAddressString()); + } + } + + internal bool IsSecureConnection + { + get + { + return _sslStatus != SslStatus.Insecure; + } + } + + internal string RawUrl + { + get + { + return _rawUrl; + } + } + + internal Version ProtocolVersion + { + get + { + return _httpVersion; + } + } + + internal string Protocol + { + get + { + if (_httpVersion.Major == 1) + { + if (_httpVersion.Minor == 1) + { + return "HTTP/1.1"; + } + else if (_httpVersion.Minor == 0) + { + return "HTTP/1.0"; + } + } + return "HTTP/" + _httpVersion.ToString(2); + } + } + + // TODO: Move this to the constructor + internal bool HasEntityBody + { + get + { + // accessing the ContentLength property delay creates m_BoundaryType + return (ContentLength64 > 0 && _contentBoundaryType == BoundaryType.ContentLength) || + _contentBoundaryType == BoundaryType.Chunked || _contentBoundaryType == BoundaryType.Multipart; + } + } + + internal SocketAddress RemoteEndPoint + { + get + { + if (_remoteEndPoint == null) + { + _remoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, OriginalBlobAddress); + } + + return _remoteEndPoint; + } + } + + internal SocketAddress LocalEndPoint + { + get + { + if (_localEndPoint == null) + { + _localEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, OriginalBlobAddress); + } + + return _localEndPoint; + } + } + + internal string RequestScheme + { + get + { + return IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; + } + } + + internal Uri RequestUri + { + get + { + if (_requestUri == null) + { + _requestUri = RequestUriBuilder.GetRequestUri( + _rawUrl, RequestScheme, _cookedUrlHost, _cookedUrlPath, _cookedUrlQuery); + } + + return _requestUri; + } + } + + internal string RequestPath + { + get + { + return RequestUriBuilder.GetRequestPath(_rawUrl, _cookedUrlPath); + } + } + + internal bool IsUpgradable + { + get + { + // HTTP.Sys allows you to upgrade anything to opaque unless content-length > 0 or chunked are specified. + return !HasEntityBody; + } + } + + internal IPrincipal User + { + get { return _user; } + } + + private unsafe IPrincipal GetUser(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* requestInfo) + { + if (requestInfo == null + || requestInfo->InfoType != UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth) + { + return null; + } + + if (requestInfo->pInfo->AuthStatus != UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + { + return null; + } + +#if NET45 + return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken)); +#else + return null; +#endif + } + + // Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be + // disposed. + internal void DetachBlob(NativeRequestContext memoryBlob) + { + if (memoryBlob != null && (object)memoryBlob == (object)_nativeRequestContext) + { + _nativeRequestContext = null; + } + } + + // Finalizes ownership of the memory blob. DetachBlob can't be called after this. + internal void ReleasePins() + { + _nativeRequestContext.ReleasePins(); + } + + // should only be called from RequestContext + public void Dispose() + { + // TODO: Verbose log + _isDisposed = true; + NativeRequestContext memoryBlob = _nativeRequestContext; + if (memoryBlob != null) + { + memoryBlob.Dispose(); + _nativeRequestContext = null; + } + _disconnectRegistration.Dispose(); + if (_requestStream != null) + { + _requestStream.Dispose(); + } + } + + internal void CheckDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(this.GetType().FullName); + } + } + + internal void SwitchToOpaqueMode() + { + if (_requestStream == null || _requestStream == Stream.Null) + { + _requestStream = new RequestStream(RequestContext); + } + } + + internal void RegisterForDisconnect(CancellationToken cancellationToken) + { + _disconnectRegistration = cancellationToken.Register(Cancel, this); + } + + private static void Cancel(object obj) + { + Request request = (Request)obj; + // Cancels owin.CallCanceled + request.RequestContext.Abort(); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs new file mode 100644 index 0000000000..5cb122006c --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs @@ -0,0 +1,388 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Authentication.ExtendedProtection; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + using LoggerFunc = Func, bool>; + using OpaqueFunc = Func, Task>; + + internal sealed class RequestContext : IDisposable, CallEnvironment.IPropertySource + { + private static readonly string[] ZeroContentLength = new[] { "0" }; + + private CallEnvironment _environment; + private OwinWebListener _server; + private Request _request; + private Response _response; + private CancellationTokenSource _cts; + private NativeRequestContext _memoryBlob; + private OpaqueFunc _opaqueCallback; + private bool _disposed; + + internal RequestContext(OwinWebListener httpListener, NativeRequestContext memoryBlob) + { + // TODO: Verbose log + _server = httpListener; + _memoryBlob = memoryBlob; + _request = new Request(this, _memoryBlob); + _response = new Response(this); + _environment = new CallEnvironment(this); + _cts = new CancellationTokenSource(); + + PopulateEnvironment(); + + _request.ReleasePins(); + } + + internal CallEnvironment Environment + { + get { return _environment; } + } + + internal Request Request + { + get + { + return _request; + } + } + + internal Response Response + { + get + { + return _response; + } + } + + internal OwinWebListener Server + { + get + { + return _server; + } + } + + internal LoggerFunc Logger + { + get { return Server.Logger; } + } + + internal SafeHandle RequestQueueHandle + { + get + { + return _server.RequestQueueHandle; + } + } + + internal ulong RequestId + { + get + { + return Request.RequestId; + } + } + + private void PopulateEnvironment() + { + // General + _environment.OwinVersion = Constants.OwinVersion; + _environment.CallCancelled = _cts.Token; + + // Server + _environment.ServerCapabilities = _server.Capabilities; + _environment.Listener = _server; + + // Request + _environment.RequestProtocol = _request.Protocol; + _environment.RequestMethod = _request.HttpMethod; + _environment.RequestScheme = _request.RequestScheme; + _environment.RequestQueryString = _request.Query; + _environment.RequestHeaders = _request.Headers; + + SetPaths(); + + _environment.ConnectionId = _request.ConnectionId; + + if (_request.IsSecureConnection) + { + _environment.LoadClientCert = LoadClientCertificateAsync; + } + + if (_request.User != null) + { + _environment.User = _request.User; + } + + // Response + _environment.ResponseStatusCode = 200; + _environment.ResponseHeaders = _response.Headers; + _environment.ResponseBody = _response.OutputStream; + _environment.SendFileAsync = _response.SendFileAsync; + + _environment.OnSendingHeaders = _response.RegisterForOnSendingHeaders; + + Contract.Assert(!_environment.IsExtraDictionaryCreated, + "All server keys should have a reserved slot in the environment."); + } + + // Find the closest matching prefix and use it to separate the request path in to path and base path. + // Scheme and port must match. Path will use a longest match. Host names are more complicated due to + // wildcards, IP addresses, etc. + private void SetPaths() + { + Prefix prefix = _server.UriPrefixes[(int)Request.ContextId]; + string orriginalPath = _request.RequestPath; + + // These paths are both unescaped already. + if (orriginalPath.Length == prefix.Path.Length - 1) + { + // They matched exactly except for the trailing slash. + _environment.RequestPathBase = orriginalPath; + _environment.RequestPath = string.Empty; + } + else + { + // url: /base/path, prefix: /base/, base: /base, path: /path + // url: /, prefix: /, base: , path: / + _environment.RequestPathBase = orriginalPath.Substring(0, prefix.Path.Length - 1); + _environment.RequestPath = orriginalPath.Substring(prefix.Path.Length - 1); + } + } + + // Lazy environment init + + public Stream GetRequestBody() + { + return _request.InputStream; + } + + public string GetRemoteIpAddress() + { + return _request.RemoteEndPoint.GetIPAddressString(); + } + + public string GetRemotePort() + { + return _request.RemoteEndPoint.GetPort().ToString(CultureInfo.InvariantCulture.NumberFormat); + } + + public string GetLocalIpAddress() + { + return _request.LocalEndPoint.GetIPAddressString(); + } + + public string GetLocalPort() + { + return _request.LocalEndPoint.GetPort().ToString(CultureInfo.InvariantCulture.NumberFormat); + } + + public bool GetIsLocal() + { + return _request.IsLocal; + } + + public bool TryGetOpaqueUpgrade(ref Action, OpaqueFunc> value) + { + if (_request.IsUpgradable) + { + value = OpaqueUpgrade; + return true; + } + return false; + } + + public bool TryGetChannelBinding(ref ChannelBinding value) + { + value = Server.GetChannelBinding(Request.ConnectionId, Request.IsSecureConnection); + return value != null; + } + + public void Dispose() + { + if (_disposed) + { + return; + } + _disposed = true; + + // TODO: Verbose log + try + { + _response.Dispose(); + } + finally + { + _request.Dispose(); + _cts.Dispose(); + } + } + + internal void Abort() + { + // TODO: Verbose log + _disposed = true; + try + { + _cts.Cancel(); + } + catch (ObjectDisposedException) + { + } + catch (AggregateException) + { + } + ForceCancelRequest(RequestQueueHandle, _request.RequestId); + _request.Dispose(); + _cts.Dispose(); + } + + internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod() + { + return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(Request.RequestBuffer, Request.OriginalBlobAddress); + } + + // This is only called while processing incoming requests. We don't have to worry about cancelling + // any response writes. + [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = + "It is safe to ignore the return value on a cancel operation because the connection is being closed")] + internal static void CancelRequest(SafeHandle requestQueueHandle, ulong requestId) + { + UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(requestQueueHandle, requestId, + IntPtr.Zero); + } + + // The request is being aborted, but large writes may be in progress. Cancel them. + internal void ForceCancelRequest(SafeHandle requestQueueHandle, ulong requestId) + { + try + { + uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(requestQueueHandle, requestId, + IntPtr.Zero); + + // Either the connection has already dropped, or the last write is in progress. + // The requestId becomes invalid as soon as the last Content-Length write starts. + // The only way to cancel now is with CancelIoEx. + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID) + { + _response.CancelLastWrite(requestQueueHandle); + } + } + catch (ObjectDisposedException) + { + // RequestQueueHandle may have been closed + } + } + + // Populates the environment ClicentCertificate. The result may be null if there is no client cert. + // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to + // enable this, but it's unclear what Http.Sys would do. + private async Task LoadClientCertificateAsync() + { + if (Request.SslStatus == SslStatus.Insecure) + { + // Non-SSL + return; + } + // TODO: Verbose log +#if NET45 + ClientCertLoader certLoader = new ClientCertLoader(this); + try + { + await certLoader.LoadClientCertificateAsync().SupressContext(); + // Populate the environment. + if (certLoader.ClientCert != null) + { + Environment.ClientCert = certLoader.ClientCert; + } + // TODO: Expose errors and exceptions? + } + catch (Exception) + { + if (certLoader != null) + { + certLoader.Dispose(); + } + throw; + } +#else + throw new NotImplementedException(); +#endif + } + + internal void OpaqueUpgrade(IDictionary parameters, OpaqueFunc callback) + { + // Parameters are ignored for now + if (Response.SentHeaders) + { + throw new InvalidOperationException(); + } + if (callback == null) + { + throw new ArgumentNullException("callback"); + } + + // Set the status code and reason phrase + Environment.ResponseStatusCode = (int)HttpStatusCode.SwitchingProtocols; + Environment.ResponseReasonPhrase = HttpReasonPhrase.Get(HttpStatusCode.SwitchingProtocols); + + // Store the callback and process it after the stack unwind. + _opaqueCallback = callback; + } + + // Called after the AppFunc completes for any necessary post-processing. + internal unsafe Task ProcessResponseAsync() + { + // If an upgrade was requested, perform it + if (!Response.SentHeaders && _opaqueCallback != null + && Environment.ResponseStatusCode == (int)HttpStatusCode.SwitchingProtocols) + { + Response.SendOpaqueUpgrade(); + + IDictionary opaqueEnv = CreateOpaqueEnvironment(); + return _opaqueCallback(opaqueEnv); + } + + return Helpers.CompletedTask(); + } + + private IDictionary CreateOpaqueEnvironment() + { + IDictionary opaqueEnv = new Dictionary(); + + opaqueEnv[Constants.OpaqueVersionKey] = Constants.OpaqueVersion; + // TODO: Separate CT? + opaqueEnv[Constants.OpaqueCallCancelledKey] = Environment.CallCancelled; + + Request.SwitchToOpaqueMode(); + Response.SwitchToOpaqueMode(); + opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.InputStream, Response.OutputStream); + + return opaqueEnv; + } + + internal void SetFatalResponse() + { + Environment.ResponseStatusCode = 500; + Environment.ResponseReasonPhrase = string.Empty; + Environment.ResponseHeaders.Clear(); + Environment.ResponseHeaders.Add(HttpKnownHeaderNames.ContentLength, ZeroContentLength); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.cs new file mode 100644 index 0000000000..2e2df172c3 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.cs @@ -0,0 +1,2544 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) Katana Contributors. All rights reserved. +// +//----------------------------------------------------------------------- +// + +using System; +using System.CodeDom.Compiler; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + [GeneratedCode("TextTemplatingFileGenerator", "")] + internal partial class RequestHeaders + { + // Tracks if individual fields have been read from native or set directly. + // Once read or set, their presence in the collection is marked by if their string[] is null or not. + private UInt32 _flag0, _flag1; + + private string[] _Accept; + private string[] _AcceptCharset; + private string[] _AcceptEncoding; + private string[] _AcceptLanguage; + private string[] _Allow; + private string[] _Authorization; + private string[] _CacheControl; + private string[] _Connection; + private string[] _ContentEncoding; + private string[] _ContentLanguage; + private string[] _ContentLength; + private string[] _ContentLocation; + private string[] _ContentMd5; + private string[] _ContentRange; + private string[] _ContentType; + private string[] _Cookie; + private string[] _Date; + private string[] _Expect; + private string[] _Expires; + private string[] _From; + private string[] _Host; + private string[] _IfMatch; + private string[] _IfModifiedSince; + private string[] _IfNoneMatch; + private string[] _IfRange; + private string[] _IfUnmodifiedSince; + private string[] _KeepAlive; + private string[] _LastModified; + private string[] _MaxForwards; + private string[] _Pragma; + private string[] _ProxyAuthorization; + private string[] _Range; + private string[] _Referer; + private string[] _Te; + private string[] _Trailer; + private string[] _TransferEncoding; + private string[] _Translate; + private string[] _Upgrade; + private string[] _UserAgent; + private string[] _Via; + private string[] _Warning; + + internal string[] Accept + { + get + { + if (!((_flag0 & 0x1u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Accept); + if (nativeValue != null) + { + _Accept = new string[] { nativeValue }; + } + _flag0 |= 0x1u; + } + return _Accept; + } + set + { + _flag0 |= 0x1u; + _Accept = value; + } + } + + internal string[] AcceptCharset + { + get + { + if (!((_flag0 & 0x2u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.AcceptCharset); + if (nativeValue != null) + { + _AcceptCharset = new string[] { nativeValue }; + } + _flag0 |= 0x2u; + } + return _AcceptCharset; + } + set + { + _flag0 |= 0x2u; + _AcceptCharset = value; + } + } + + internal string[] AcceptEncoding + { + get + { + if (!((_flag0 & 0x4u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.AcceptEncoding); + if (nativeValue != null) + { + _AcceptEncoding = new string[] { nativeValue }; + } + _flag0 |= 0x4u; + } + return _AcceptEncoding; + } + set + { + _flag0 |= 0x4u; + _AcceptEncoding = value; + } + } + + internal string[] AcceptLanguage + { + get + { + if (!((_flag0 & 0x8u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.AcceptLanguage); + if (nativeValue != null) + { + _AcceptLanguage = new string[] { nativeValue }; + } + _flag0 |= 0x8u; + } + return _AcceptLanguage; + } + set + { + _flag0 |= 0x8u; + _AcceptLanguage = value; + } + } + + internal string[] Allow + { + get + { + if (!((_flag0 & 0x10u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Allow); + if (nativeValue != null) + { + _Allow = new string[] { nativeValue }; + } + _flag0 |= 0x10u; + } + return _Allow; + } + set + { + _flag0 |= 0x10u; + _Allow = value; + } + } + + internal string[] Authorization + { + get + { + if (!((_flag0 & 0x20u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Authorization); + if (nativeValue != null) + { + _Authorization = new string[] { nativeValue }; + } + _flag0 |= 0x20u; + } + return _Authorization; + } + set + { + _flag0 |= 0x20u; + _Authorization = value; + } + } + + internal string[] CacheControl + { + get + { + if (!((_flag0 & 0x40u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.CacheControl); + if (nativeValue != null) + { + _CacheControl = new string[] { nativeValue }; + } + _flag0 |= 0x40u; + } + return _CacheControl; + } + set + { + _flag0 |= 0x40u; + _CacheControl = value; + } + } + + internal string[] Connection + { + get + { + if (!((_flag0 & 0x80u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Connection); + if (nativeValue != null) + { + _Connection = new string[] { nativeValue }; + } + _flag0 |= 0x80u; + } + return _Connection; + } + set + { + _flag0 |= 0x80u; + _Connection = value; + } + } + + internal string[] ContentEncoding + { + get + { + if (!((_flag0 & 0x100u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentEncoding); + if (nativeValue != null) + { + _ContentEncoding = new string[] { nativeValue }; + } + _flag0 |= 0x100u; + } + return _ContentEncoding; + } + set + { + _flag0 |= 0x100u; + _ContentEncoding = value; + } + } + + internal string[] ContentLanguage + { + get + { + if (!((_flag0 & 0x200u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentLanguage); + if (nativeValue != null) + { + _ContentLanguage = new string[] { nativeValue }; + } + _flag0 |= 0x200u; + } + return _ContentLanguage; + } + set + { + _flag0 |= 0x200u; + _ContentLanguage = value; + } + } + + internal string[] ContentLength + { + get + { + if (!((_flag0 & 0x400u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentLength); + if (nativeValue != null) + { + _ContentLength = new string[] { nativeValue }; + } + _flag0 |= 0x400u; + } + return _ContentLength; + } + set + { + _flag0 |= 0x400u; + _ContentLength = value; + } + } + + internal string[] ContentLocation + { + get + { + if (!((_flag0 & 0x800u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentLocation); + if (nativeValue != null) + { + _ContentLocation = new string[] { nativeValue }; + } + _flag0 |= 0x800u; + } + return _ContentLocation; + } + set + { + _flag0 |= 0x800u; + _ContentLocation = value; + } + } + + internal string[] ContentMd5 + { + get + { + if (!((_flag0 & 0x1000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentMd5); + if (nativeValue != null) + { + _ContentMd5 = new string[] { nativeValue }; + } + _flag0 |= 0x1000u; + } + return _ContentMd5; + } + set + { + _flag0 |= 0x1000u; + _ContentMd5 = value; + } + } + + internal string[] ContentRange + { + get + { + if (!((_flag0 & 0x2000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentRange); + if (nativeValue != null) + { + _ContentRange = new string[] { nativeValue }; + } + _flag0 |= 0x2000u; + } + return _ContentRange; + } + set + { + _flag0 |= 0x2000u; + _ContentRange = value; + } + } + + internal string[] ContentType + { + get + { + if (!((_flag0 & 0x4000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentType); + if (nativeValue != null) + { + _ContentType = new string[] { nativeValue }; + } + _flag0 |= 0x4000u; + } + return _ContentType; + } + set + { + _flag0 |= 0x4000u; + _ContentType = value; + } + } + + internal string[] Cookie + { + get + { + if (!((_flag0 & 0x8000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Cookie); + if (nativeValue != null) + { + _Cookie = new string[] { nativeValue }; + } + _flag0 |= 0x8000u; + } + return _Cookie; + } + set + { + _flag0 |= 0x8000u; + _Cookie = value; + } + } + + internal string[] Date + { + get + { + if (!((_flag0 & 0x10000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Date); + if (nativeValue != null) + { + _Date = new string[] { nativeValue }; + } + _flag0 |= 0x10000u; + } + return _Date; + } + set + { + _flag0 |= 0x10000u; + _Date = value; + } + } + + internal string[] Expect + { + get + { + if (!((_flag0 & 0x20000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Expect); + if (nativeValue != null) + { + _Expect = new string[] { nativeValue }; + } + _flag0 |= 0x20000u; + } + return _Expect; + } + set + { + _flag0 |= 0x20000u; + _Expect = value; + } + } + + internal string[] Expires + { + get + { + if (!((_flag0 & 0x40000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Expires); + if (nativeValue != null) + { + _Expires = new string[] { nativeValue }; + } + _flag0 |= 0x40000u; + } + return _Expires; + } + set + { + _flag0 |= 0x40000u; + _Expires = value; + } + } + + internal string[] From + { + get + { + if (!((_flag0 & 0x80000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.From); + if (nativeValue != null) + { + _From = new string[] { nativeValue }; + } + _flag0 |= 0x80000u; + } + return _From; + } + set + { + _flag0 |= 0x80000u; + _From = value; + } + } + + internal string[] Host + { + get + { + if (!((_flag0 & 0x100000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Host); + if (nativeValue != null) + { + _Host = new string[] { nativeValue }; + } + _flag0 |= 0x100000u; + } + return _Host; + } + set + { + _flag0 |= 0x100000u; + _Host = value; + } + } + + internal string[] IfMatch + { + get + { + if (!((_flag0 & 0x200000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfMatch); + if (nativeValue != null) + { + _IfMatch = new string[] { nativeValue }; + } + _flag0 |= 0x200000u; + } + return _IfMatch; + } + set + { + _flag0 |= 0x200000u; + _IfMatch = value; + } + } + + internal string[] IfModifiedSince + { + get + { + if (!((_flag0 & 0x400000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfModifiedSince); + if (nativeValue != null) + { + _IfModifiedSince = new string[] { nativeValue }; + } + _flag0 |= 0x400000u; + } + return _IfModifiedSince; + } + set + { + _flag0 |= 0x400000u; + _IfModifiedSince = value; + } + } + + internal string[] IfNoneMatch + { + get + { + if (!((_flag0 & 0x800000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfNoneMatch); + if (nativeValue != null) + { + _IfNoneMatch = new string[] { nativeValue }; + } + _flag0 |= 0x800000u; + } + return _IfNoneMatch; + } + set + { + _flag0 |= 0x800000u; + _IfNoneMatch = value; + } + } + + internal string[] IfRange + { + get + { + if (!((_flag0 & 0x1000000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfRange); + if (nativeValue != null) + { + _IfRange = new string[] { nativeValue }; + } + _flag0 |= 0x1000000u; + } + return _IfRange; + } + set + { + _flag0 |= 0x1000000u; + _IfRange = value; + } + } + + internal string[] IfUnmodifiedSince + { + get + { + if (!((_flag0 & 0x2000000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfUnmodifiedSince); + if (nativeValue != null) + { + _IfUnmodifiedSince = new string[] { nativeValue }; + } + _flag0 |= 0x2000000u; + } + return _IfUnmodifiedSince; + } + set + { + _flag0 |= 0x2000000u; + _IfUnmodifiedSince = value; + } + } + + internal string[] KeepAlive + { + get + { + if (!((_flag0 & 0x4000000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.KeepAlive); + if (nativeValue != null) + { + _KeepAlive = new string[] { nativeValue }; + } + _flag0 |= 0x4000000u; + } + return _KeepAlive; + } + set + { + _flag0 |= 0x4000000u; + _KeepAlive = value; + } + } + + internal string[] LastModified + { + get + { + if (!((_flag0 & 0x8000000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.LastModified); + if (nativeValue != null) + { + _LastModified = new string[] { nativeValue }; + } + _flag0 |= 0x8000000u; + } + return _LastModified; + } + set + { + _flag0 |= 0x8000000u; + _LastModified = value; + } + } + + internal string[] MaxForwards + { + get + { + if (!((_flag0 & 0x10000000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.MaxForwards); + if (nativeValue != null) + { + _MaxForwards = new string[] { nativeValue }; + } + _flag0 |= 0x10000000u; + } + return _MaxForwards; + } + set + { + _flag0 |= 0x10000000u; + _MaxForwards = value; + } + } + + internal string[] Pragma + { + get + { + if (!((_flag0 & 0x20000000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Pragma); + if (nativeValue != null) + { + _Pragma = new string[] { nativeValue }; + } + _flag0 |= 0x20000000u; + } + return _Pragma; + } + set + { + _flag0 |= 0x20000000u; + _Pragma = value; + } + } + + internal string[] ProxyAuthorization + { + get + { + if (!((_flag0 & 0x40000000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.ProxyAuthorization); + if (nativeValue != null) + { + _ProxyAuthorization = new string[] { nativeValue }; + } + _flag0 |= 0x40000000u; + } + return _ProxyAuthorization; + } + set + { + _flag0 |= 0x40000000u; + _ProxyAuthorization = value; + } + } + + internal string[] Range + { + get + { + if (!((_flag0 & 0x80000000u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Range); + if (nativeValue != null) + { + _Range = new string[] { nativeValue }; + } + _flag0 |= 0x80000000u; + } + return _Range; + } + set + { + _flag0 |= 0x80000000u; + _Range = value; + } + } + + internal string[] Referer + { + get + { + if (!((_flag1 & 0x1u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Referer); + if (nativeValue != null) + { + _Referer = new string[] { nativeValue }; + } + _flag1 |= 0x1u; + } + return _Referer; + } + set + { + _flag1 |= 0x1u; + _Referer = value; + } + } + + internal string[] Te + { + get + { + if (!((_flag1 & 0x2u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Te); + if (nativeValue != null) + { + _Te = new string[] { nativeValue }; + } + _flag1 |= 0x2u; + } + return _Te; + } + set + { + _flag1 |= 0x2u; + _Te = value; + } + } + + internal string[] Trailer + { + get + { + if (!((_flag1 & 0x4u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Trailer); + if (nativeValue != null) + { + _Trailer = new string[] { nativeValue }; + } + _flag1 |= 0x4u; + } + return _Trailer; + } + set + { + _flag1 |= 0x4u; + _Trailer = value; + } + } + + internal string[] TransferEncoding + { + get + { + if (!((_flag1 & 0x8u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.TransferEncoding); + if (nativeValue != null) + { + _TransferEncoding = new string[] { nativeValue }; + } + _flag1 |= 0x8u; + } + return _TransferEncoding; + } + set + { + _flag1 |= 0x8u; + _TransferEncoding = value; + } + } + + internal string[] Translate + { + get + { + if (!((_flag1 & 0x10u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Translate); + if (nativeValue != null) + { + _Translate = new string[] { nativeValue }; + } + _flag1 |= 0x10u; + } + return _Translate; + } + set + { + _flag1 |= 0x10u; + _Translate = value; + } + } + + internal string[] Upgrade + { + get + { + if (!((_flag1 & 0x20u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Upgrade); + if (nativeValue != null) + { + _Upgrade = new string[] { nativeValue }; + } + _flag1 |= 0x20u; + } + return _Upgrade; + } + set + { + _flag1 |= 0x20u; + _Upgrade = value; + } + } + + internal string[] UserAgent + { + get + { + if (!((_flag1 & 0x40u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.UserAgent); + if (nativeValue != null) + { + _UserAgent = new string[] { nativeValue }; + } + _flag1 |= 0x40u; + } + return _UserAgent; + } + set + { + _flag1 |= 0x40u; + _UserAgent = value; + } + } + + internal string[] Via + { + get + { + if (!((_flag1 & 0x80u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Via); + if (nativeValue != null) + { + _Via = new string[] { nativeValue }; + } + _flag1 |= 0x80u; + } + return _Via; + } + set + { + _flag1 |= 0x80u; + _Via = value; + } + } + + internal string[] Warning + { + get + { + if (!((_flag1 & 0x100u) != 0)) + { + string nativeValue = GetKnownHeader(HttpSysRequestHeader.Warning); + if (nativeValue != null) + { + _Warning = new string[] { nativeValue }; + } + _flag1 |= 0x100u; + } + return _Warning; + } + set + { + _flag1 |= 0x100u; + _Warning = value; + } + } + + private bool PropertiesContainsKey(string key) + { + switch (key.Length) + { + case 2: + if (string.Equals(key, "Te", StringComparison.OrdinalIgnoreCase)) + { + return Te != null; + } + break; + case 3: + if (string.Equals(key, "Via", StringComparison.OrdinalIgnoreCase)) + { + return Via != null; + } + break; + case 4: + if (string.Equals(key, "Date", StringComparison.OrdinalIgnoreCase)) + { + return Date != null; + } + if (string.Equals(key, "From", StringComparison.OrdinalIgnoreCase)) + { + return From != null; + } + if (string.Equals(key, "Host", StringComparison.OrdinalIgnoreCase)) + { + return Host != null; + } + break; + case 5: + if (string.Equals(key, "Allow", StringComparison.OrdinalIgnoreCase)) + { + return Allow != null; + } + if (string.Equals(key, "Range", StringComparison.OrdinalIgnoreCase)) + { + return Range != null; + } + break; + case 6: + if (string.Equals(key, "Accept", StringComparison.OrdinalIgnoreCase)) + { + return Accept != null; + } + if (string.Equals(key, "Cookie", StringComparison.OrdinalIgnoreCase)) + { + return Cookie != null; + } + if (string.Equals(key, "Expect", StringComparison.OrdinalIgnoreCase)) + { + return Expect != null; + } + if (string.Equals(key, "Pragma", StringComparison.OrdinalIgnoreCase)) + { + return Pragma != null; + } + break; + case 7: + if (string.Equals(key, "Expires", StringComparison.OrdinalIgnoreCase)) + { + return Expires != null; + } + if (string.Equals(key, "Referer", StringComparison.OrdinalIgnoreCase)) + { + return Referer != null; + } + if (string.Equals(key, "Trailer", StringComparison.OrdinalIgnoreCase)) + { + return Trailer != null; + } + if (string.Equals(key, "Upgrade", StringComparison.OrdinalIgnoreCase)) + { + return Upgrade != null; + } + if (string.Equals(key, "Warning", StringComparison.OrdinalIgnoreCase)) + { + return Warning != null; + } + break; + case 8: + if (string.Equals(key, "If-Match", StringComparison.OrdinalIgnoreCase)) + { + return IfMatch != null; + } + if (string.Equals(key, "If-Range", StringComparison.OrdinalIgnoreCase)) + { + return IfRange != null; + } + break; + case 9: + if (string.Equals(key, "Translate", StringComparison.OrdinalIgnoreCase)) + { + return Translate != null; + } + break; + case 10: + if (string.Equals(key, "Connection", StringComparison.OrdinalIgnoreCase)) + { + return Connection != null; + } + if (string.Equals(key, "Keep-Alive", StringComparison.OrdinalIgnoreCase)) + { + return KeepAlive != null; + } + if (string.Equals(key, "User-Agent", StringComparison.OrdinalIgnoreCase)) + { + return UserAgent != null; + } + break; + case 11: + if (string.Equals(key, "Content-Md5", StringComparison.OrdinalIgnoreCase)) + { + return ContentMd5 != null; + } + break; + case 12: + if (string.Equals(key, "Content-Type", StringComparison.OrdinalIgnoreCase)) + { + return ContentType != null; + } + if (string.Equals(key, "Max-Forwards", StringComparison.OrdinalIgnoreCase)) + { + return MaxForwards != null; + } + break; + case 13: + if (string.Equals(key, "Authorization", StringComparison.OrdinalIgnoreCase)) + { + return Authorization != null; + } + if (string.Equals(key, "Cache-Control", StringComparison.OrdinalIgnoreCase)) + { + return CacheControl != null; + } + if (string.Equals(key, "Content-Range", StringComparison.OrdinalIgnoreCase)) + { + return ContentRange != null; + } + if (string.Equals(key, "If-None-Match", StringComparison.OrdinalIgnoreCase)) + { + return IfNoneMatch != null; + } + if (string.Equals(key, "Last-Modified", StringComparison.OrdinalIgnoreCase)) + { + return LastModified != null; + } + break; + case 14: + if (string.Equals(key, "Accept-Charset", StringComparison.OrdinalIgnoreCase)) + { + return AcceptCharset != null; + } + if (string.Equals(key, "Content-Length", StringComparison.OrdinalIgnoreCase)) + { + return ContentLength != null; + } + break; + case 15: + if (string.Equals(key, "Accept-Encoding", StringComparison.OrdinalIgnoreCase)) + { + return AcceptEncoding != null; + } + if (string.Equals(key, "Accept-Language", StringComparison.OrdinalIgnoreCase)) + { + return AcceptLanguage != null; + } + break; + case 16: + if (string.Equals(key, "Content-Encoding", StringComparison.OrdinalIgnoreCase)) + { + return ContentEncoding != null; + } + if (string.Equals(key, "Content-Language", StringComparison.OrdinalIgnoreCase)) + { + return ContentLanguage != null; + } + if (string.Equals(key, "Content-Location", StringComparison.OrdinalIgnoreCase)) + { + return ContentLocation != null; + } + break; + case 17: + if (string.Equals(key, "If-Modified-Since", StringComparison.OrdinalIgnoreCase)) + { + return IfModifiedSince != null; + } + if (string.Equals(key, "Transfer-Encoding", StringComparison.OrdinalIgnoreCase)) + { + return TransferEncoding != null; + } + break; + case 19: + if (string.Equals(key, "If-Unmodified-Since", StringComparison.OrdinalIgnoreCase)) + { + return IfUnmodifiedSince != null; + } + if (string.Equals(key, "Proxy-Authorization", StringComparison.OrdinalIgnoreCase)) + { + return ProxyAuthorization != null; + } + break; + } + return false; + } + + private bool PropertiesTryGetValue(string key, out string[] value) + { + switch (key.Length) + { + case 2: + if (string.Equals(key, "Te", StringComparison.OrdinalIgnoreCase)) + { + value = Te; + return value != null; + } + break; + case 3: + if (string.Equals(key, "Via", StringComparison.OrdinalIgnoreCase)) + { + value = Via; + return value != null; + } + break; + case 4: + if (string.Equals(key, "Date", StringComparison.OrdinalIgnoreCase)) + { + value = Date; + return value != null; + } + if (string.Equals(key, "From", StringComparison.OrdinalIgnoreCase)) + { + value = From; + return value != null; + } + if (string.Equals(key, "Host", StringComparison.OrdinalIgnoreCase)) + { + value = Host; + return value != null; + } + break; + case 5: + if (string.Equals(key, "Allow", StringComparison.OrdinalIgnoreCase)) + { + value = Allow; + return value != null; + } + if (string.Equals(key, "Range", StringComparison.OrdinalIgnoreCase)) + { + value = Range; + return value != null; + } + break; + case 6: + if (string.Equals(key, "Accept", StringComparison.OrdinalIgnoreCase)) + { + value = Accept; + return value != null; + } + if (string.Equals(key, "Cookie", StringComparison.OrdinalIgnoreCase)) + { + value = Cookie; + return value != null; + } + if (string.Equals(key, "Expect", StringComparison.OrdinalIgnoreCase)) + { + value = Expect; + return value != null; + } + if (string.Equals(key, "Pragma", StringComparison.OrdinalIgnoreCase)) + { + value = Pragma; + return value != null; + } + break; + case 7: + if (string.Equals(key, "Expires", StringComparison.OrdinalIgnoreCase)) + { + value = Expires; + return value != null; + } + if (string.Equals(key, "Referer", StringComparison.OrdinalIgnoreCase)) + { + value = Referer; + return value != null; + } + if (string.Equals(key, "Trailer", StringComparison.OrdinalIgnoreCase)) + { + value = Trailer; + return value != null; + } + if (string.Equals(key, "Upgrade", StringComparison.OrdinalIgnoreCase)) + { + value = Upgrade; + return value != null; + } + if (string.Equals(key, "Warning", StringComparison.OrdinalIgnoreCase)) + { + value = Warning; + return value != null; + } + break; + case 8: + if (string.Equals(key, "If-Match", StringComparison.OrdinalIgnoreCase)) + { + value = IfMatch; + return value != null; + } + if (string.Equals(key, "If-Range", StringComparison.OrdinalIgnoreCase)) + { + value = IfRange; + return value != null; + } + break; + case 9: + if (string.Equals(key, "Translate", StringComparison.OrdinalIgnoreCase)) + { + value = Translate; + return value != null; + } + break; + case 10: + if (string.Equals(key, "Connection", StringComparison.OrdinalIgnoreCase)) + { + value = Connection; + return value != null; + } + if (string.Equals(key, "Keep-Alive", StringComparison.OrdinalIgnoreCase)) + { + value = KeepAlive; + return value != null; + } + if (string.Equals(key, "User-Agent", StringComparison.OrdinalIgnoreCase)) + { + value = UserAgent; + return value != null; + } + break; + case 11: + if (string.Equals(key, "Content-Md5", StringComparison.OrdinalIgnoreCase)) + { + value = ContentMd5; + return value != null; + } + break; + case 12: + if (string.Equals(key, "Content-Type", StringComparison.OrdinalIgnoreCase)) + { + value = ContentType; + return value != null; + } + if (string.Equals(key, "Max-Forwards", StringComparison.OrdinalIgnoreCase)) + { + value = MaxForwards; + return value != null; + } + break; + case 13: + if (string.Equals(key, "Authorization", StringComparison.OrdinalIgnoreCase)) + { + value = Authorization; + return value != null; + } + if (string.Equals(key, "Cache-Control", StringComparison.OrdinalIgnoreCase)) + { + value = CacheControl; + return value != null; + } + if (string.Equals(key, "Content-Range", StringComparison.OrdinalIgnoreCase)) + { + value = ContentRange; + return value != null; + } + if (string.Equals(key, "If-None-Match", StringComparison.OrdinalIgnoreCase)) + { + value = IfNoneMatch; + return value != null; + } + if (string.Equals(key, "Last-Modified", StringComparison.OrdinalIgnoreCase)) + { + value = LastModified; + return value != null; + } + break; + case 14: + if (string.Equals(key, "Accept-Charset", StringComparison.OrdinalIgnoreCase)) + { + value = AcceptCharset; + return value != null; + } + if (string.Equals(key, "Content-Length", StringComparison.OrdinalIgnoreCase)) + { + value = ContentLength; + return value != null; + } + break; + case 15: + if (string.Equals(key, "Accept-Encoding", StringComparison.OrdinalIgnoreCase)) + { + value = AcceptEncoding; + return value != null; + } + if (string.Equals(key, "Accept-Language", StringComparison.OrdinalIgnoreCase)) + { + value = AcceptLanguage; + return value != null; + } + break; + case 16: + if (string.Equals(key, "Content-Encoding", StringComparison.OrdinalIgnoreCase)) + { + value = ContentEncoding; + return value != null; + } + if (string.Equals(key, "Content-Language", StringComparison.OrdinalIgnoreCase)) + { + value = ContentLanguage; + return value != null; + } + if (string.Equals(key, "Content-Location", StringComparison.OrdinalIgnoreCase)) + { + value = ContentLocation; + return value != null; + } + break; + case 17: + if (string.Equals(key, "If-Modified-Since", StringComparison.OrdinalIgnoreCase)) + { + value = IfModifiedSince; + return value != null; + } + if (string.Equals(key, "Transfer-Encoding", StringComparison.OrdinalIgnoreCase)) + { + value = TransferEncoding; + return value != null; + } + break; + case 19: + if (string.Equals(key, "If-Unmodified-Since", StringComparison.OrdinalIgnoreCase)) + { + value = IfUnmodifiedSince; + return value != null; + } + if (string.Equals(key, "Proxy-Authorization", StringComparison.OrdinalIgnoreCase)) + { + value = ProxyAuthorization; + return value != null; + } + break; + } + value = null; + return false; + } + + private bool PropertiesTrySetValue(string key, string[] value) + { + switch (key.Length) + { + case 2: + if (string.Equals(key, "Te", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x2u; + Te = value; + return true; + } + break; + case 3: + if (string.Equals(key, "Via", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x80u; + Via = value; + return true; + } + break; + case 4: + if (string.Equals(key, "Date", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x10000u; + Date = value; + return true; + } + if (string.Equals(key, "From", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x80000u; + From = value; + return true; + } + if (string.Equals(key, "Host", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x100000u; + Host = value; + return true; + } + break; + case 5: + if (string.Equals(key, "Allow", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x10u; + Allow = value; + return true; + } + if (string.Equals(key, "Range", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x80000000u; + Range = value; + return true; + } + break; + case 6: + if (string.Equals(key, "Accept", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x1u; + Accept = value; + return true; + } + if (string.Equals(key, "Cookie", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x8000u; + Cookie = value; + return true; + } + if (string.Equals(key, "Expect", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x20000u; + Expect = value; + return true; + } + if (string.Equals(key, "Pragma", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x20000000u; + Pragma = value; + return true; + } + break; + case 7: + if (string.Equals(key, "Expires", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x40000u; + Expires = value; + return true; + } + if (string.Equals(key, "Referer", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x1u; + Referer = value; + return true; + } + if (string.Equals(key, "Trailer", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x4u; + Trailer = value; + return true; + } + if (string.Equals(key, "Upgrade", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x20u; + Upgrade = value; + return true; + } + if (string.Equals(key, "Warning", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x100u; + Warning = value; + return true; + } + break; + case 8: + if (string.Equals(key, "If-Match", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x200000u; + IfMatch = value; + return true; + } + if (string.Equals(key, "If-Range", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x1000000u; + IfRange = value; + return true; + } + break; + case 9: + if (string.Equals(key, "Translate", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x10u; + Translate = value; + return true; + } + break; + case 10: + if (string.Equals(key, "Connection", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x80u; + Connection = value; + return true; + } + if (string.Equals(key, "Keep-Alive", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x4000000u; + KeepAlive = value; + return true; + } + if (string.Equals(key, "User-Agent", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x40u; + UserAgent = value; + return true; + } + break; + case 11: + if (string.Equals(key, "Content-Md5", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x1000u; + ContentMd5 = value; + return true; + } + break; + case 12: + if (string.Equals(key, "Content-Type", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x4000u; + ContentType = value; + return true; + } + if (string.Equals(key, "Max-Forwards", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x10000000u; + MaxForwards = value; + return true; + } + break; + case 13: + if (string.Equals(key, "Authorization", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x20u; + Authorization = value; + return true; + } + if (string.Equals(key, "Cache-Control", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x40u; + CacheControl = value; + return true; + } + if (string.Equals(key, "Content-Range", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x2000u; + ContentRange = value; + return true; + } + if (string.Equals(key, "If-None-Match", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x800000u; + IfNoneMatch = value; + return true; + } + if (string.Equals(key, "Last-Modified", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x8000000u; + LastModified = value; + return true; + } + break; + case 14: + if (string.Equals(key, "Accept-Charset", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x2u; + AcceptCharset = value; + return true; + } + if (string.Equals(key, "Content-Length", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x400u; + ContentLength = value; + return true; + } + break; + case 15: + if (string.Equals(key, "Accept-Encoding", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x4u; + AcceptEncoding = value; + return true; + } + if (string.Equals(key, "Accept-Language", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x8u; + AcceptLanguage = value; + return true; + } + break; + case 16: + if (string.Equals(key, "Content-Encoding", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x100u; + ContentEncoding = value; + return true; + } + if (string.Equals(key, "Content-Language", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x200u; + ContentLanguage = value; + return true; + } + if (string.Equals(key, "Content-Location", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x800u; + ContentLocation = value; + return true; + } + break; + case 17: + if (string.Equals(key, "If-Modified-Since", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x400000u; + IfModifiedSince = value; + return true; + } + if (string.Equals(key, "Transfer-Encoding", StringComparison.OrdinalIgnoreCase)) + { + _flag1 |= 0x8u; + TransferEncoding = value; + return true; + } + break; + case 19: + if (string.Equals(key, "If-Unmodified-Since", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x2000000u; + IfUnmodifiedSince = value; + return true; + } + if (string.Equals(key, "Proxy-Authorization", StringComparison.OrdinalIgnoreCase)) + { + _flag0 |= 0x40000000u; + ProxyAuthorization = value; + return true; + } + break; + } + return false; + } + + private bool PropertiesTryRemove(string key) + { + switch (key.Length) + { + case 2: + if (_Te != null + && string.Equals(key, "Te", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x2u) != 0); + Te = null; + return wasSet; + } + break; + case 3: + if (_Via != null + && string.Equals(key, "Via", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x80u) != 0); + Via = null; + return wasSet; + } + break; + case 4: + if (_Date != null + && string.Equals(key, "Date", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x10000u) != 0); + Date = null; + return wasSet; + } + if (_From != null + && string.Equals(key, "From", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x80000u) != 0); + From = null; + return wasSet; + } + if (_Host != null + && string.Equals(key, "Host", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x100000u) != 0); + Host = null; + return wasSet; + } + break; + case 5: + if (_Allow != null + && string.Equals(key, "Allow", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x10u) != 0); + Allow = null; + return wasSet; + } + if (_Range != null + && string.Equals(key, "Range", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x80000000u) != 0); + Range = null; + return wasSet; + } + break; + case 6: + if (_Accept != null + && string.Equals(key, "Accept", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x1u) != 0); + Accept = null; + return wasSet; + } + if (_Cookie != null + && string.Equals(key, "Cookie", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x8000u) != 0); + Cookie = null; + return wasSet; + } + if (_Expect != null + && string.Equals(key, "Expect", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x20000u) != 0); + Expect = null; + return wasSet; + } + if (_Pragma != null + && string.Equals(key, "Pragma", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x20000000u) != 0); + Pragma = null; + return wasSet; + } + break; + case 7: + if (_Expires != null + && string.Equals(key, "Expires", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x40000u) != 0); + Expires = null; + return wasSet; + } + if (_Referer != null + && string.Equals(key, "Referer", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x1u) != 0); + Referer = null; + return wasSet; + } + if (_Trailer != null + && string.Equals(key, "Trailer", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x4u) != 0); + Trailer = null; + return wasSet; + } + if (_Upgrade != null + && string.Equals(key, "Upgrade", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x20u) != 0); + Upgrade = null; + return wasSet; + } + if (_Warning != null + && string.Equals(key, "Warning", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x100u) != 0); + Warning = null; + return wasSet; + } + break; + case 8: + if (_IfMatch != null + && string.Equals(key, "If-Match", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x200000u) != 0); + IfMatch = null; + return wasSet; + } + if (_IfRange != null + && string.Equals(key, "If-Range", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x1000000u) != 0); + IfRange = null; + return wasSet; + } + break; + case 9: + if (_Translate != null + && string.Equals(key, "Translate", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x10u) != 0); + Translate = null; + return wasSet; + } + break; + case 10: + if (_Connection != null + && string.Equals(key, "Connection", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x80u) != 0); + Connection = null; + return wasSet; + } + if (_KeepAlive != null + && string.Equals(key, "Keep-Alive", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x4000000u) != 0); + KeepAlive = null; + return wasSet; + } + if (_UserAgent != null + && string.Equals(key, "User-Agent", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x40u) != 0); + UserAgent = null; + return wasSet; + } + break; + case 11: + if (_ContentMd5 != null + && string.Equals(key, "Content-Md5", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x1000u) != 0); + ContentMd5 = null; + return wasSet; + } + break; + case 12: + if (_ContentType != null + && string.Equals(key, "Content-Type", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x4000u) != 0); + ContentType = null; + return wasSet; + } + if (_MaxForwards != null + && string.Equals(key, "Max-Forwards", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x10000000u) != 0); + MaxForwards = null; + return wasSet; + } + break; + case 13: + if (_Authorization != null + && string.Equals(key, "Authorization", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x20u) != 0); + Authorization = null; + return wasSet; + } + if (_CacheControl != null + && string.Equals(key, "Cache-Control", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x40u) != 0); + CacheControl = null; + return wasSet; + } + if (_ContentRange != null + && string.Equals(key, "Content-Range", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x2000u) != 0); + ContentRange = null; + return wasSet; + } + if (_IfNoneMatch != null + && string.Equals(key, "If-None-Match", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x800000u) != 0); + IfNoneMatch = null; + return wasSet; + } + if (_LastModified != null + && string.Equals(key, "Last-Modified", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x8000000u) != 0); + LastModified = null; + return wasSet; + } + break; + case 14: + if (_AcceptCharset != null + && string.Equals(key, "Accept-Charset", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x2u) != 0); + AcceptCharset = null; + return wasSet; + } + if (_ContentLength != null + && string.Equals(key, "Content-Length", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x400u) != 0); + ContentLength = null; + return wasSet; + } + break; + case 15: + if (_AcceptEncoding != null + && string.Equals(key, "Accept-Encoding", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x4u) != 0); + AcceptEncoding = null; + return wasSet; + } + if (_AcceptLanguage != null + && string.Equals(key, "Accept-Language", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x8u) != 0); + AcceptLanguage = null; + return wasSet; + } + break; + case 16: + if (_ContentEncoding != null + && string.Equals(key, "Content-Encoding", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x100u) != 0); + ContentEncoding = null; + return wasSet; + } + if (_ContentLanguage != null + && string.Equals(key, "Content-Language", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x200u) != 0); + ContentLanguage = null; + return wasSet; + } + if (_ContentLocation != null + && string.Equals(key, "Content-Location", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x800u) != 0); + ContentLocation = null; + return wasSet; + } + break; + case 17: + if (_IfModifiedSince != null + && string.Equals(key, "If-Modified-Since", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x400000u) != 0); + IfModifiedSince = null; + return wasSet; + } + if (_TransferEncoding != null + && string.Equals(key, "Transfer-Encoding", StringComparison.Ordinal)) + { + bool wasSet = ((_flag1 & 0x8u) != 0); + TransferEncoding = null; + return wasSet; + } + break; + case 19: + if (_IfUnmodifiedSince != null + && string.Equals(key, "If-Unmodified-Since", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x2000000u) != 0); + IfUnmodifiedSince = null; + return wasSet; + } + if (_ProxyAuthorization != null + && string.Equals(key, "Proxy-Authorization", StringComparison.Ordinal)) + { + bool wasSet = ((_flag0 & 0x40000000u) != 0); + ProxyAuthorization = null; + return wasSet; + } + break; + } + return false; + } + + private IEnumerable PropertiesKeys() + { + if (Accept != null) + { + yield return "Accept"; + } + if (AcceptCharset != null) + { + yield return "Accept-Charset"; + } + if (AcceptEncoding != null) + { + yield return "Accept-Encoding"; + } + if (AcceptLanguage != null) + { + yield return "Accept-Language"; + } + if (Allow != null) + { + yield return "Allow"; + } + if (Authorization != null) + { + yield return "Authorization"; + } + if (CacheControl != null) + { + yield return "Cache-Control"; + } + if (Connection != null) + { + yield return "Connection"; + } + if (ContentEncoding != null) + { + yield return "Content-Encoding"; + } + if (ContentLanguage != null) + { + yield return "Content-Language"; + } + if (ContentLength != null) + { + yield return "Content-Length"; + } + if (ContentLocation != null) + { + yield return "Content-Location"; + } + if (ContentMd5 != null) + { + yield return "Content-Md5"; + } + if (ContentRange != null) + { + yield return "Content-Range"; + } + if (ContentType != null) + { + yield return "Content-Type"; + } + if (Cookie != null) + { + yield return "Cookie"; + } + if (Date != null) + { + yield return "Date"; + } + if (Expect != null) + { + yield return "Expect"; + } + if (Expires != null) + { + yield return "Expires"; + } + if (From != null) + { + yield return "From"; + } + if (Host != null) + { + yield return "Host"; + } + if (IfMatch != null) + { + yield return "If-Match"; + } + if (IfModifiedSince != null) + { + yield return "If-Modified-Since"; + } + if (IfNoneMatch != null) + { + yield return "If-None-Match"; + } + if (IfRange != null) + { + yield return "If-Range"; + } + if (IfUnmodifiedSince != null) + { + yield return "If-Unmodified-Since"; + } + if (KeepAlive != null) + { + yield return "Keep-Alive"; + } + if (LastModified != null) + { + yield return "Last-Modified"; + } + if (MaxForwards != null) + { + yield return "Max-Forwards"; + } + if (Pragma != null) + { + yield return "Pragma"; + } + if (ProxyAuthorization != null) + { + yield return "Proxy-Authorization"; + } + if (Range != null) + { + yield return "Range"; + } + if (Referer != null) + { + yield return "Referer"; + } + if (Te != null) + { + yield return "Te"; + } + if (Trailer != null) + { + yield return "Trailer"; + } + if (TransferEncoding != null) + { + yield return "Transfer-Encoding"; + } + if (Translate != null) + { + yield return "Translate"; + } + if (Upgrade != null) + { + yield return "Upgrade"; + } + if (UserAgent != null) + { + yield return "User-Agent"; + } + if (Via != null) + { + yield return "Via"; + } + if (Warning != null) + { + yield return "Warning"; + } + } + + private IEnumerable PropertiesValues() + { + if (Accept != null) + { + yield return Accept; + } + if (AcceptCharset != null) + { + yield return AcceptCharset; + } + if (AcceptEncoding != null) + { + yield return AcceptEncoding; + } + if (AcceptLanguage != null) + { + yield return AcceptLanguage; + } + if (Allow != null) + { + yield return Allow; + } + if (Authorization != null) + { + yield return Authorization; + } + if (CacheControl != null) + { + yield return CacheControl; + } + if (Connection != null) + { + yield return Connection; + } + if (ContentEncoding != null) + { + yield return ContentEncoding; + } + if (ContentLanguage != null) + { + yield return ContentLanguage; + } + if (ContentLength != null) + { + yield return ContentLength; + } + if (ContentLocation != null) + { + yield return ContentLocation; + } + if (ContentMd5 != null) + { + yield return ContentMd5; + } + if (ContentRange != null) + { + yield return ContentRange; + } + if (ContentType != null) + { + yield return ContentType; + } + if (Cookie != null) + { + yield return Cookie; + } + if (Date != null) + { + yield return Date; + } + if (Expect != null) + { + yield return Expect; + } + if (Expires != null) + { + yield return Expires; + } + if (From != null) + { + yield return From; + } + if (Host != null) + { + yield return Host; + } + if (IfMatch != null) + { + yield return IfMatch; + } + if (IfModifiedSince != null) + { + yield return IfModifiedSince; + } + if (IfNoneMatch != null) + { + yield return IfNoneMatch; + } + if (IfRange != null) + { + yield return IfRange; + } + if (IfUnmodifiedSince != null) + { + yield return IfUnmodifiedSince; + } + if (KeepAlive != null) + { + yield return KeepAlive; + } + if (LastModified != null) + { + yield return LastModified; + } + if (MaxForwards != null) + { + yield return MaxForwards; + } + if (Pragma != null) + { + yield return Pragma; + } + if (ProxyAuthorization != null) + { + yield return ProxyAuthorization; + } + if (Range != null) + { + yield return Range; + } + if (Referer != null) + { + yield return Referer; + } + if (Te != null) + { + yield return Te; + } + if (Trailer != null) + { + yield return Trailer; + } + if (TransferEncoding != null) + { + yield return TransferEncoding; + } + if (Translate != null) + { + yield return Translate; + } + if (Upgrade != null) + { + yield return Upgrade; + } + if (UserAgent != null) + { + yield return UserAgent; + } + if (Via != null) + { + yield return Via; + } + if (Warning != null) + { + yield return Warning; + } + } + + private IEnumerable> PropertiesEnumerable() + { + if (Accept != null) + { + yield return new KeyValuePair("Accept", Accept); + } + if (AcceptCharset != null) + { + yield return new KeyValuePair("Accept-Charset", AcceptCharset); + } + if (AcceptEncoding != null) + { + yield return new KeyValuePair("Accept-Encoding", AcceptEncoding); + } + if (AcceptLanguage != null) + { + yield return new KeyValuePair("Accept-Language", AcceptLanguage); + } + if (Allow != null) + { + yield return new KeyValuePair("Allow", Allow); + } + if (Authorization != null) + { + yield return new KeyValuePair("Authorization", Authorization); + } + if (CacheControl != null) + { + yield return new KeyValuePair("Cache-Control", CacheControl); + } + if (Connection != null) + { + yield return new KeyValuePair("Connection", Connection); + } + if (ContentEncoding != null) + { + yield return new KeyValuePair("Content-Encoding", ContentEncoding); + } + if (ContentLanguage != null) + { + yield return new KeyValuePair("Content-Language", ContentLanguage); + } + if (ContentLength != null) + { + yield return new KeyValuePair("Content-Length", ContentLength); + } + if (ContentLocation != null) + { + yield return new KeyValuePair("Content-Location", ContentLocation); + } + if (ContentMd5 != null) + { + yield return new KeyValuePair("Content-Md5", ContentMd5); + } + if (ContentRange != null) + { + yield return new KeyValuePair("Content-Range", ContentRange); + } + if (ContentType != null) + { + yield return new KeyValuePair("Content-Type", ContentType); + } + if (Cookie != null) + { + yield return new KeyValuePair("Cookie", Cookie); + } + if (Date != null) + { + yield return new KeyValuePair("Date", Date); + } + if (Expect != null) + { + yield return new KeyValuePair("Expect", Expect); + } + if (Expires != null) + { + yield return new KeyValuePair("Expires", Expires); + } + if (From != null) + { + yield return new KeyValuePair("From", From); + } + if (Host != null) + { + yield return new KeyValuePair("Host", Host); + } + if (IfMatch != null) + { + yield return new KeyValuePair("If-Match", IfMatch); + } + if (IfModifiedSince != null) + { + yield return new KeyValuePair("If-Modified-Since", IfModifiedSince); + } + if (IfNoneMatch != null) + { + yield return new KeyValuePair("If-None-Match", IfNoneMatch); + } + if (IfRange != null) + { + yield return new KeyValuePair("If-Range", IfRange); + } + if (IfUnmodifiedSince != null) + { + yield return new KeyValuePair("If-Unmodified-Since", IfUnmodifiedSince); + } + if (KeepAlive != null) + { + yield return new KeyValuePair("Keep-Alive", KeepAlive); + } + if (LastModified != null) + { + yield return new KeyValuePair("Last-Modified", LastModified); + } + if (MaxForwards != null) + { + yield return new KeyValuePair("Max-Forwards", MaxForwards); + } + if (Pragma != null) + { + yield return new KeyValuePair("Pragma", Pragma); + } + if (ProxyAuthorization != null) + { + yield return new KeyValuePair("Proxy-Authorization", ProxyAuthorization); + } + if (Range != null) + { + yield return new KeyValuePair("Range", Range); + } + if (Referer != null) + { + yield return new KeyValuePair("Referer", Referer); + } + if (Te != null) + { + yield return new KeyValuePair("Te", Te); + } + if (Trailer != null) + { + yield return new KeyValuePair("Trailer", Trailer); + } + if (TransferEncoding != null) + { + yield return new KeyValuePair("Transfer-Encoding", TransferEncoding); + } + if (Translate != null) + { + yield return new KeyValuePair("Translate", Translate); + } + if (Upgrade != null) + { + yield return new KeyValuePair("Upgrade", Upgrade); + } + if (UserAgent != null) + { + yield return new KeyValuePair("User-Agent", UserAgent); + } + if (Via != null) + { + yield return new KeyValuePair("Via", Via); + } + if (Warning != null) + { + yield return new KeyValuePair("Warning", Warning); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.tt b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.tt new file mode 100644 index 0000000000..2b339e4640 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.tt @@ -0,0 +1,218 @@ +<#@ template language="C#" #> +<#@ assembly name="System.Core.dll" #> +<#@ import namespace="System.Linq" #> +<# +var props = new[] +{ + new { Key = "Accept", Name = "Accept", ID = "HttpSysRequestHeader.Accept" }, + new { Key = "Accept-Charset", Name = "AcceptCharset", ID = "HttpSysRequestHeader.AcceptCharset" }, + new { Key = "Accept-Encoding", Name = "AcceptEncoding", ID = "HttpSysRequestHeader.AcceptEncoding" }, + new { Key = "Accept-Language", Name = "AcceptLanguage", ID = "HttpSysRequestHeader.AcceptLanguage" }, + new { Key = "Allow", Name = "Allow", ID = "HttpSysRequestHeader.Allow" }, + new { Key = "Authorization", Name = "Authorization", ID = "HttpSysRequestHeader.Authorization" }, + new { Key = "Cache-Control", Name = "CacheControl", ID = "HttpSysRequestHeader.CacheControl" }, + new { Key = "Connection", Name = "Connection", ID = "HttpSysRequestHeader.Connection" }, + new { Key = "Content-Encoding", Name = "ContentEncoding", ID = "HttpSysRequestHeader.ContentEncoding" }, + new { Key = "Content-Language", Name = "ContentLanguage", ID = "HttpSysRequestHeader.ContentLanguage" }, + new { Key = "Content-Length", Name = "ContentLength", ID = "HttpSysRequestHeader.ContentLength" }, + new { Key = "Content-Location", Name = "ContentLocation", ID = "HttpSysRequestHeader.ContentLocation" }, + new { Key = "Content-Md5", Name = "ContentMd5", ID = "HttpSysRequestHeader.ContentMd5" }, + new { Key = "Content-Range", Name = "ContentRange", ID = "HttpSysRequestHeader.ContentRange" }, + new { Key = "Content-Type", Name = "ContentType", ID = "HttpSysRequestHeader.ContentType" }, + new { Key = "Cookie", Name = "Cookie", ID = "HttpSysRequestHeader.Cookie" }, + new { Key = "Date", Name = "Date", ID = "HttpSysRequestHeader.Date" }, + new { Key = "Expect", Name = "Expect", ID = "HttpSysRequestHeader.Expect" }, + new { Key = "Expires", Name = "Expires", ID = "HttpSysRequestHeader.Expires" }, + new { Key = "From", Name = "From", ID = "HttpSysRequestHeader.From" }, + new { Key = "Host", Name = "Host", ID = "HttpSysRequestHeader.Host" }, + new { Key = "If-Match", Name = "IfMatch", ID = "HttpSysRequestHeader.IfMatch" }, + new { Key = "If-Modified-Since", Name = "IfModifiedSince", ID = "HttpSysRequestHeader.IfModifiedSince" }, + new { Key = "If-None-Match", Name = "IfNoneMatch", ID = "HttpSysRequestHeader.IfNoneMatch" }, + new { Key = "If-Range", Name = "IfRange", ID = "HttpSysRequestHeader.IfRange" }, + new { Key = "If-Unmodified-Since", Name = "IfUnmodifiedSince", ID = "HttpSysRequestHeader.IfUnmodifiedSince" }, + new { Key = "Keep-Alive", Name = "KeepAlive", ID = "HttpSysRequestHeader.KeepAlive" }, + new { Key = "Last-Modified", Name = "LastModified", ID = "HttpSysRequestHeader.LastModified" }, + new { Key = "Max-Forwards", Name = "MaxForwards", ID = "HttpSysRequestHeader.MaxForwards" }, + new { Key = "Pragma", Name = "Pragma", ID = "HttpSysRequestHeader.Pragma" }, + new { Key = "Proxy-Authorization", Name = "ProxyAuthorization", ID = "HttpSysRequestHeader.ProxyAuthorization" }, + new { Key = "Range", Name = "Range", ID = "HttpSysRequestHeader.Range" }, + new { Key = "Referer", Name = "Referer", ID = "HttpSysRequestHeader.Referer" }, + new { Key = "Te", Name = "Te", ID = "HttpSysRequestHeader.Te" }, + new { Key = "Trailer", Name = "Trailer", ID = "HttpSysRequestHeader.Trailer" }, + new { Key = "Transfer-Encoding", Name = "TransferEncoding", ID = "HttpSysRequestHeader.TransferEncoding" }, + new { Key = "Translate", Name = "Translate", ID = "HttpSysRequestHeader.Translate" }, + new { Key = "Upgrade", Name = "Upgrade", ID = "HttpSysRequestHeader.Upgrade" }, + new { Key = "User-Agent", Name = "UserAgent", ID = "HttpSysRequestHeader.UserAgent" }, + new { Key = "Via", Name = "Via", ID = "HttpSysRequestHeader.Via" }, + new { Key = "Warning", Name = "Warning", ID = "HttpSysRequestHeader.Warning" }, +}.Select((prop, Index)=>new {prop.Key, prop.Name, prop.ID, Index}); + +var lengths = props.GroupBy(prop=>prop.Key.Length).OrderBy(prop=>prop.Key); + + +Func IsRead = Index => "((_flag" + (Index / 32) + " & 0x" + (1<<(Index % 32)).ToString("x") + "u) != 0)"; +Func MarkRead = Index => "_flag" + (Index / 32) + " |= 0x" + (1<<(Index % 32)).ToString("x") + "u"; +Func Clear = Index => "_flag" + (Index / 32) + " &= ~0x" + (1<<(Index % 32)).ToString("x") + "u"; +#> +//----------------------------------------------------------------------- +// +// Copyright (c) Katana Contributors. All rights reserved. +// +//----------------------------------------------------------------------- +// + +using System; +using System.CodeDom.Compiler; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Owin.Host.WebListener +{ + [GeneratedCode("TextTemplatingFileGenerator", "")] + internal partial class RequestHeaders + { + // Tracks if individual fields have been read from native or set directly. + // Once read or set, their presence in the collection is marked by if their string[] is null or not. + private UInt32 _flag0, _flag1; + +<# foreach(var prop in props) { #> + private string[] _<#=prop.Name#>; +<# } #> + +<# foreach(var prop in props) { #> + internal string[] <#=prop.Name#> + { + get + { + if (!<#=IsRead(prop.Index)#>) + { + string nativeValue = GetKnownHeader(<#=prop.ID#>); + if (nativeValue != null) + { + _<#=prop.Name#> = new string[] { nativeValue }; + } + <#=MarkRead(prop.Index)#>; + } + return _<#=prop.Name#>; + } + set + { + <#=MarkRead(prop.Index)#>; + _<#=prop.Name#> = value; + } + } + +<# } #> + private bool PropertiesContainsKey(string key) + { + switch (key.Length) + { +<# foreach(var length in lengths) { #> + case <#=length.Key#>: +<# foreach(var prop in length) { #> + if (string.Equals(key, "<#=prop.Key#>", StringComparison.OrdinalIgnoreCase)) + { + return <#=prop.Name#> != null; + } +<# } #> + break; +<# } #> + } + return false; + } + + private bool PropertiesTryGetValue(string key, out string[] value) + { + switch (key.Length) + { +<# foreach(var length in lengths) { #> + case <#=length.Key#>: +<# foreach(var prop in length) { #> + if (string.Equals(key, "<#=prop.Key#>", StringComparison.OrdinalIgnoreCase)) + { + value = <#=prop.Name#>; + return value != null; + } +<# } #> + break; +<# } #> + } + value = null; + return false; + } + + private bool PropertiesTrySetValue(string key, string[] value) + { + switch (key.Length) + { +<# foreach(var length in lengths) { #> + case <#=length.Key#>: +<# foreach(var prop in length) { #> + if (string.Equals(key, "<#=prop.Key#>", StringComparison.OrdinalIgnoreCase)) + { + <#=MarkRead(prop.Index)#>; + <#=prop.Name#> = value; + return true; + } +<# } #> + break; +<# } #> + } + return false; + } + + private bool PropertiesTryRemove(string key) + { + switch (key.Length) + { +<# foreach(var length in lengths) { #> + case <#=length.Key#>: +<# foreach(var prop in length) { #> + if (_<#=prop.Name#> != null + && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) + { + bool wasSet = <#=IsRead(prop.Index)#>; + <#=prop.Name#> = null; + return wasSet; + } +<# } #> + break; +<# } #> + } + return false; + } + + private IEnumerable PropertiesKeys() + { +<# foreach(var prop in props) { #> + if (<#=prop.Name#> != null) + { + yield return "<#=prop.Key#>"; + } +<# } #> + } + + private IEnumerable PropertiesValues() + { +<# foreach(var prop in props) { #> + if (<#=prop.Name#> != null) + { + yield return <#=prop.Name#>; + } +<# } #> + } + + private IEnumerable> PropertiesEnumerable() + { +<# foreach(var prop in props) { #> + if (<#=prop.Name#> != null) + { + yield return new KeyValuePair("<#=prop.Key#>", <#=prop.Name#>); + } +<# } #> + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.cs new file mode 100644 index 0000000000..9e43ab86e5 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.cs @@ -0,0 +1,167 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- +// Copyright 2011-2012 Katana contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal partial class RequestHeaders : IDictionary + { + private IDictionary _extra; + private NativeRequestContext _requestMemoryBlob; + + internal RequestHeaders(NativeRequestContext requestMemoryBlob) + { + _requestMemoryBlob = requestMemoryBlob; + } + + private IDictionary Extra + { + get + { + if (_extra == null) + { + var newDict = new Dictionary(StringComparer.OrdinalIgnoreCase); + GetUnknownHeaders(newDict); + Interlocked.CompareExchange(ref _extra, newDict, null); + } + return _extra; + } + } + + string[] IDictionary.this[string key] + { + get + { + string[] value; + return PropertiesTryGetValue(key, out value) ? value : Extra[key]; + } + set + { + if (!PropertiesTrySetValue(key, value)) + { + Extra[key] = value; + } + } + } + + private string GetKnownHeader(HttpSysRequestHeader header) + { + return UnsafeNclNativeMethods.HttpApi.GetKnownHeader(_requestMemoryBlob.RequestBuffer, + _requestMemoryBlob.OriginalBlobAddress, (int)header); + } + + private void GetUnknownHeaders(IDictionary extra) + { + UnsafeNclNativeMethods.HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer, + _requestMemoryBlob.OriginalBlobAddress); + } + + void IDictionary.Add(string key, string[] value) + { + if (!PropertiesTrySetValue(key, value)) + { + Extra.Add(key, value); + } + } + + bool IDictionary.ContainsKey(string key) + { + return PropertiesContainsKey(key) || Extra.ContainsKey(key); + } + + ICollection IDictionary.Keys + { + get { return PropertiesKeys().Concat(Extra.Keys).ToArray(); } + } + + bool IDictionary.Remove(string key) + { + // Although this is a mutating operation, Extra is used instead of StrongExtra, + // because if a real dictionary has not been allocated the default behavior of the + // nil dictionary is perfectly fine. + return PropertiesTryRemove(key) || Extra.Remove(key); + } + + bool IDictionary.TryGetValue(string key, out string[] value) + { + return PropertiesTryGetValue(key, out value) || Extra.TryGetValue(key, out value); + } + + ICollection IDictionary.Values + { + get { return PropertiesValues().Concat(Extra.Values).ToArray(); } + } + + void ICollection>.Add(KeyValuePair item) + { + ((IDictionary)this).Add(item.Key, item.Value); + } + + void ICollection>.Clear() + { + foreach (var key in PropertiesKeys()) + { + PropertiesTryRemove(key); + } + Extra.Clear(); + } + + bool ICollection>.Contains(KeyValuePair item) + { + object value; + return ((IDictionary)this).TryGetValue(item.Key, out value) && Object.Equals(value, item.Value); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + PropertiesEnumerable().Concat(Extra).ToArray().CopyTo(array, arrayIndex); + } + + int ICollection>.Count + { + get { return PropertiesKeys().Count() + Extra.Count; } + } + + bool ICollection>.IsReadOnly + { + get { return false; } + } + + bool ICollection>.Remove(KeyValuePair item) + { + return ((IDictionary)this).Contains(item) && + ((IDictionary)this).Remove(item.Key); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return PropertiesEnumerable().Concat(Extra).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IDictionary)this).GetEnumerator(); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs new file mode 100644 index 0000000000..5c73f0d41c --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs @@ -0,0 +1,614 @@ +// ------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class RequestStream : Stream + { + private const int MaxReadSize = 0x20000; // http.sys recommends we limit reads to 128k + + private RequestContext _requestContext; + private uint _dataChunkOffset; + private int _dataChunkIndex; + private bool _closed; + + internal RequestStream(RequestContext httpContext) + { + _requestContext = httpContext; + } + + public override bool CanSeek + { + get + { + return false; + } + } + + public override bool CanWrite + { + get + { + return false; + } + } + + public override bool CanRead + { + get + { + return true; + } + } + + public override long Length + { + get + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + } + + public override long Position + { + get + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + set + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + + public override void Flush() + { + throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); + } + + public override unsafe int Read([In, Out] byte[] buffer, int offset, int size) + { + 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"); + } + if (size == 0 || _closed) + { + // TODO: zero sized buffer should be invalid. + return 0; + } + // TODO: Verbose log parameters + + uint dataRead = 0; + + if (_dataChunkIndex != -1) + { + dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + } + + if (_dataChunkIndex == -1 && dataRead < size) + { + uint statusCode = 0; + uint extraDataRead = 0; + offset += (int)dataRead; + size -= (int)dataRead; + + // the http.sys team recommends that we limit the size to 128kb + if (size > MaxReadSize) + { + size = MaxReadSize; + } + + fixed (byte* pBuffer = buffer) + { + // issue unmanaged blocking call + + uint flags = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + flags, + (IntPtr)(pBuffer + offset), + (uint)size, + out extraDataRead, + SafeNativeOverlapped.Zero); + + dataRead += extraDataRead; + } + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + Exception exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_requestContext.Logger, "Read", exception); + throw exception; + } + UpdateAfterRead(statusCode, dataRead); + } + + // TODO: Verbose log dump data read + return (int)dataRead; + } + + private void UpdateAfterRead(uint statusCode, uint dataRead) + { + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF || dataRead == 0) + { + Dispose(); + } + } + +#if NET45 + public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#else + public unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#endif + { + 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"); + } + if (size == 0 || _closed) + { + RequestStreamAsyncResult result = new RequestStreamAsyncResult(this, state, callback); + result.Complete(0); + return result; + } + // TODO: Verbose log parameters + + RequestStreamAsyncResult asyncResult = null; + + uint dataRead = 0; + if (_dataChunkIndex != -1) + { + dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + if (_dataChunkIndex != -1 && dataRead == size) + { + asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, 0); + asyncResult.Complete((int)dataRead); + } + } + + if (_dataChunkIndex == -1 && dataRead < size) + { + uint statusCode = 0; + offset += (int)dataRead; + size -= (int)dataRead; + + // the http.sys team recommends that we limit the size to 128kb + if (size > MaxReadSize) + { + size = MaxReadSize; + } + + asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, dataRead); + uint bytesReturned; + + try + { + fixed (byte* pBuffer = buffer) + { + uint flags = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + flags, + asyncResult.PinnedBuffer, + (uint)size, + out bytesReturned, + asyncResult.NativeOverlapped); + } + } + catch (Exception e) + { + LogHelper.LogException(_requestContext.Logger, "BeginRead", e); + asyncResult.Dispose(); + throw; + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + asyncResult = new RequestStreamAsyncResult(this, state, callback, dataRead); + asyncResult.Complete((int)bytesReturned); + } + else + { + Exception exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_requestContext.Logger, "BeginRead", exception); + throw exception; + } + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + OwinWebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.IOCompleted(statusCode, bytesReturned); + } + } + return asyncResult; + } + +#if NET45 + public override int EndRead(IAsyncResult asyncResult) +#else + public int EndRead(IAsyncResult asyncResult) +#endif + { + if (asyncResult == null) + { + throw new ArgumentNullException("asyncResult"); + } + RequestStreamAsyncResult castedAsyncResult = asyncResult as RequestStreamAsyncResult; + if (castedAsyncResult == null || castedAsyncResult.RequestStream != this) + { + throw new ArgumentException(Resources.Exception_WrongIAsyncResult, "asyncResult"); + } + if (castedAsyncResult.EndCalled) + { + throw new InvalidOperationException(Resources.Exception_EndCalledMultipleTimes); + } + castedAsyncResult.EndCalled = true; + // wait & then check for errors + // Throws on failure + int dataRead = castedAsyncResult.Task.Result; + // TODO: Verbose log #dataRead. + return dataRead; + } + + public override unsafe Task ReadAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken) + { + 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"); + } + if (_closed) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (size == 0) + { + return Task.FromResult(0); + } + // TODO: Needs full cancellation integration + cancellationToken.ThrowIfCancellationRequested(); + // TODO: Verbose log parameters + + RequestStreamAsyncResult asyncResult = null; + + uint dataRead = 0; + if (_dataChunkIndex != -1) + { + dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + if (_dataChunkIndex != -1 && dataRead == size) + { + UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead); + // TODO: Verbose log #dataRead + return Task.FromResult((int)dataRead); + } + } + + if (_dataChunkIndex == -1 && dataRead < size) + { + uint statusCode = 0; + offset += (int)dataRead; + size -= (int)dataRead; + + // the http.sys team recommends that we limit the size to 128kb + if (size > MaxReadSize) + { + size = MaxReadSize; + } + + asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead); + uint bytesReturned; + + try + { + uint flags = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + flags, + asyncResult.PinnedBuffer, + (uint)size, + out bytesReturned, + asyncResult.NativeOverlapped); + } + catch (Exception e) + { + asyncResult.Dispose(); + LogHelper.LogException(_requestContext.Logger, "ReadAsync", e); + throw; + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + uint totalRead = dataRead + bytesReturned; + UpdateAfterRead(statusCode, totalRead); + // TODO: Verbose log totalRead + return Task.FromResult((int)totalRead); + } + else + { + Exception exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_requestContext.Logger, "ReadAsync", exception); + throw exception; + } + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + OwinWebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.Dispose(); + uint totalRead = dataRead + bytesReturned; + UpdateAfterRead(statusCode, totalRead); + // TODO: Verbose log + return Task.FromResult((int)totalRead); + } + } + return asyncResult.Task; + } + + public override void Write(byte[] buffer, int offset, int size) + { + throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); + } + +#if NET45 + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#else + public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#endif + { + throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); + } + +#if NET45 + public override void EndWrite(IAsyncResult asyncResult) +#else + public void EndWrite(IAsyncResult asyncResult) +#endif + { + throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); + } + + protected override void Dispose(bool disposing) + { + try + { + _closed = true; + } + finally + { + base.Dispose(disposing); + } + } + + private unsafe class RequestStreamAsyncResult : IAsyncResult, IDisposable + { + private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(Callback); + + private SafeNativeOverlapped _overlapped; + private IntPtr _pinnedBuffer; + private uint _dataAlreadyRead = 0; + private TaskCompletionSource _tcs; + private RequestStream _requestStream; + private AsyncCallback _callback; + + internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback) + { + _requestStream = requestStream; + _tcs = new TaskCompletionSource(userState); + _callback = callback; + } + + internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, uint dataAlreadyRead) + : this(requestStream, userState, callback) + { + _dataAlreadyRead = dataAlreadyRead; + } + + internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead) + : this(requestStream, userState, callback) + { + _dataAlreadyRead = dataAlreadyRead; + Overlapped overlapped = new Overlapped(); + overlapped.AsyncResult = this; + _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, buffer)); + _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); + } + + internal RequestStream RequestStream + { + get { return _requestStream; } + } + + internal SafeNativeOverlapped NativeOverlapped + { + get { return _overlapped; } + } + + internal IntPtr PinnedBuffer + { + get { return _pinnedBuffer; } + } + + internal uint DataAlreadyRead + { + get { return _dataAlreadyRead; } + } + + internal Task Task + { + get { return _tcs.Task; } + } + + internal bool EndCalled { get; set; } + + internal void IOCompleted(uint errorCode, uint numBytes) + { + IOCompleted(this, errorCode, numBytes); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting to callback")] + private static void IOCompleted(RequestStreamAsyncResult asyncResult, uint errorCode, uint numBytes) + { + try + { + if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + asyncResult.Fail(new WebListenerException((int)errorCode)); + } + else + { + // TODO: Verbose log dump data read + asyncResult.Complete((int)numBytes, errorCode); + } + } + catch (Exception e) + { + asyncResult.Fail(e); + } + } + + private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) + { + Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); + RequestStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as RequestStreamAsyncResult; + + IOCompleted(asyncResult, errorCode, numBytes); + } + + internal void Complete(int read, uint errorCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + if (_tcs.TrySetResult(read + (int)DataAlreadyRead)) + { + RequestStream.UpdateAfterRead((uint)errorCode, (uint)(read + DataAlreadyRead)); + if (_callback != null) + { + try + { + _callback(this); + } + catch (Exception) + { + // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. + } + } + } + } + + internal void Fail(Exception ex) + { + if (_tcs.TrySetException(ex) && _callback != null) + { + try + { + _callback(this); + } + catch (Exception) + { + // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. + // TODO: Log + } + } + } + + [SuppressMessage("Microsoft.Usage", "CA2216:DisposableTypesShouldDeclareFinalizer", Justification = "The disposable resource referenced does have a finalizer.")] + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_overlapped != null) + { + _overlapped.Dispose(); + } + } + } + + public object AsyncState + { + get { return _tcs.Task.AsyncState; } + } + + public WaitHandle AsyncWaitHandle + { + get { return ((IAsyncResult)_tcs.Task).AsyncWaitHandle; } + } + + public bool CompletedSynchronously + { + get { return ((IAsyncResult)_tcs.Task).CompletedSynchronously; } + } + + public bool IsCompleted + { + get { return _tcs.Task.IsCompleted; } + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestUriBuilder.cs new file mode 100644 index 0000000000..697934fc93 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestUriBuilder.cs @@ -0,0 +1,569 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text; + +namespace Microsoft.AspNet.Server.WebListener +{ + // We don't use the cooked URL because http.sys unescapes all percent-encoded values. However, + // we also can't just use the raw Uri, since http.sys supports not only Utf-8, but also ANSI/DBCS and + // Unicode code points. System.Uri only supports Utf-8. + // The purpose of this class is to convert all ANSI, DBCS, and Unicode code points into percent encoded + // Utf-8 characters. + internal sealed class RequestUriBuilder + { + private static readonly bool UseCookedRequestUrl; + private static readonly Encoding Utf8Encoding; + private static readonly Encoding AnsiEncoding; + + private readonly string _rawUri; + private readonly string _cookedUriScheme; + private readonly string _cookedUriHost; + private readonly string _cookedUriPath; + private readonly string _cookedUriQuery; + + // This field is used to build the final request Uri string from the Uri parts passed to the ctor. + private StringBuilder _requestUriString; + + // The raw path is parsed by looping through all characters from left to right. 'rawOctets' + // is used to store consecutive percent encoded octets as actual byte values: e.g. for path /pa%C3%84th%2F/ + // rawOctets will be set to { 0xC3, 0x84 } when we reach character 't' and it will be { 0x2F } when + // we reach the final '/'. I.e. after a sequence of percent encoded octets ends, we use rawOctets as + // input to the encoding and percent encode the resulting string into UTF-8 octets. + // + // When parsing ANSI (Latin 1) encoded path '/pa%C4th/', %C4 will be added to rawOctets and when + // we reach 't', the content of rawOctets { 0xC4 } will be fed into the ANSI encoding. The resulting + // string '' will be percent encoded into UTF-8 octets and appended to requestUriString. The final + // path will be '/pa%C3%84th/', where '%C3%84' is the UTF-8 percent encoded character ''. + private List _rawOctets; + private string _rawPath; + + // Holds the final request Uri. + private Uri _requestUri; + + static RequestUriBuilder() + { + // TODO: False triggers more detailed/correct parsing, but it's rather slow. + UseCookedRequestUrl = true; // SettingsSectionInternal.Section.HttpListenerUnescapeRequestUrl; + Utf8Encoding = new UTF8Encoding(false, true); +#if NET45 + AnsiEncoding = Encoding.GetEncoding(0, new EncoderExceptionFallback(), new DecoderExceptionFallback()); +#else + AnsiEncoding = Utf8Encoding; +#endif + } + + private RequestUriBuilder(string rawUri, string cookedUriScheme, string cookedUriHost, + string cookedUriPath, string cookedUriQuery) + { + Debug.Assert(!string.IsNullOrEmpty(rawUri), "Empty raw URL."); + Debug.Assert(!string.IsNullOrEmpty(cookedUriScheme), "Empty cooked URL scheme."); + Debug.Assert(!string.IsNullOrEmpty(cookedUriHost), "Empty cooked URL host."); + Debug.Assert(!string.IsNullOrEmpty(cookedUriPath), "Empty cooked URL path."); + + this._rawUri = rawUri; + this._cookedUriScheme = cookedUriScheme; + this._cookedUriHost = cookedUriHost; + this._cookedUriPath = AddSlashToAsteriskOnlyPath(cookedUriPath); + this._cookedUriQuery = cookedUriQuery ?? string.Empty; + } + + private RequestUriBuilder(string rawUri, string cookedUriPath) + { + Debug.Assert(!string.IsNullOrEmpty(rawUri), "Empty raw URL."); + Debug.Assert(!string.IsNullOrEmpty(cookedUriPath), "Empty cooked URL path."); + + this._rawUri = rawUri; + this._cookedUriScheme = string.Empty; + this._cookedUriHost = string.Empty; + this._cookedUriPath = AddSlashToAsteriskOnlyPath(cookedUriPath); + this._cookedUriQuery = string.Empty; + } + + private enum ParsingResult + { + Success, + InvalidString, + EncodingError + } + + private enum EncodingType + { + Primary, + Secondary + } + + public static Uri GetRequestUri(string rawUri, string cookedUriScheme, string cookedUriHost, + string cookedUriPath, string cookedUriQuery) + { + RequestUriBuilder builder = new RequestUriBuilder(rawUri, + cookedUriScheme, cookedUriHost, cookedUriPath, cookedUriQuery); + + return builder.Build(); + } + + private Uri Build() + { + // if the user enabled the "use raw Uri" setting in section, we'll use the raw + // path rather than the cooked path. + if (UseCookedRequestUrl) + { + // corresponds to pre-4.0 behavior: use the cooked URI. + BuildRequestUriUsingCookedPath(); + + if (_requestUri == null) + { + BuildRequestUriUsingRawPath(); + } + } + else + { + BuildRequestUriUsingRawPath(); + + if (_requestUri == null) + { + BuildRequestUriUsingCookedPath(); + } + } + + return _requestUri; + } + + // Process only the path. + internal static string GetRequestPath(string rawUri, string cookedUriPath) + { + RequestUriBuilder builder = new RequestUriBuilder(rawUri, cookedUriPath); + + return builder.GetPath(); + } + + private string GetPath() + { + if (UseCookedRequestUrl) + { + return _cookedUriPath; + } + + // Initialize 'rawPath' only if really needed; i.e. if we build the request Uri from the raw Uri. + _rawPath = GetPath(_rawUri); + + // If HTTP.sys only parses Utf-8, we can safely use the raw path: it must be a valid Utf-8 string. + if (!HttpSysSettings.EnableNonUtf8 || string.IsNullOrEmpty(_rawPath)) + { + if (string.IsNullOrEmpty(_rawPath)) + { + _rawPath = "/"; + } + return _rawPath; + } + + // Try to check the raw path using first the primary encoding (according to http.sys settings); + // if it fails try the secondary encoding. + _rawOctets = new List(); + _requestUriString = new StringBuilder(); + ParsingResult result = ParseRawPath(GetEncoding(EncodingType.Primary)); + if (result == ParsingResult.EncodingError) + { + _rawOctets = new List(); + _requestUriString = new StringBuilder(); + result = ParseRawPath(GetEncoding(EncodingType.Secondary)); + } + + if (result == ParsingResult.Success) + { + return _requestUriString.ToString(); + } + + // Fallback + return _cookedUriPath; + } + + private void BuildRequestUriUsingCookedPath() + { + bool isValid = Uri.TryCreate(_cookedUriScheme + Constants.SchemeDelimiter + _cookedUriHost + _cookedUriPath + + _cookedUriQuery, UriKind.Absolute, out _requestUri); + + // Creating a Uri from the cooked Uri should really always work: If not, we log at least. + if (!isValid) + { + LogWarning("BuildRequestUriUsingCookedPath", "Unable to create URI: " + _cookedUriScheme + Constants.SchemeDelimiter + + _cookedUriHost + _cookedUriPath + _cookedUriQuery); + } + } + + private void BuildRequestUriUsingRawPath() + { + bool isValid = false; + + // Initialize 'rawPath' only if really needed; i.e. if we build the request Uri from the raw Uri. + _rawPath = GetPath(_rawUri); + + // If HTTP.sys only parses Utf-8, we can safely use the raw path: it must be a valid Utf-8 string. + if (!HttpSysSettings.EnableNonUtf8 || string.IsNullOrEmpty(_rawPath)) + { + string path = _rawPath; + if (string.IsNullOrEmpty(path)) + { + path = "/"; + Debug.Assert(string.IsNullOrEmpty(_cookedUriQuery), + "Query is only allowed if there is a non-empty path. At least '/' path required."); + } + + isValid = Uri.TryCreate(_cookedUriScheme + Constants.SchemeDelimiter + _cookedUriHost + path + _cookedUriQuery, + UriKind.Absolute, out _requestUri); + } + else + { + // Try to check the raw path using first the primary encoding (according to http.sys settings); + // if it fails try the secondary encoding. + ParsingResult result = BuildRequestUriUsingRawPath(GetEncoding(EncodingType.Primary)); + if (result == ParsingResult.EncodingError) + { + Encoding secondaryEncoding = GetEncoding(EncodingType.Secondary); + result = BuildRequestUriUsingRawPath(secondaryEncoding); + } + isValid = (result == ParsingResult.Success) ? true : false; + } + + // Log that we weren't able to create a Uri from the raw string. + if (!isValid) + { + LogWarning("BuildRequestUriUsingRawPath", "Unable to create Uri: " + _cookedUriScheme + Constants.SchemeDelimiter + + _cookedUriHost + _rawPath + _cookedUriQuery); + } + } + + private static Encoding GetEncoding(EncodingType type) + { + Debug.Assert(HttpSysSettings.EnableNonUtf8, + "If 'EnableNonUtf8' is false we shouldn't require an encoding. It's always Utf-8."); + /* This is mucking up the profiler for some reason. + Debug.Assert((type == EncodingType.Primary) || (type == EncodingType.Secondary), + "Unknown 'EncodingType' value: " + type.ToString()); + */ + if (((type == EncodingType.Primary) && (!HttpSysSettings.FavorUtf8)) || + ((type == EncodingType.Secondary) && (HttpSysSettings.FavorUtf8))) + { + return AnsiEncoding; + } + else + { + return Utf8Encoding; + } + } + + private ParsingResult BuildRequestUriUsingRawPath(Encoding encoding) + { + Debug.Assert(encoding != null, "'encoding' must be assigned."); + Debug.Assert(!string.IsNullOrEmpty(_rawPath), "'rawPath' must have at least one character."); + + _rawOctets = new List(); + _requestUriString = new StringBuilder(); + _requestUriString.Append(_cookedUriScheme); + _requestUriString.Append(Constants.SchemeDelimiter); + _requestUriString.Append(_cookedUriHost); + + ParsingResult result = ParseRawPath(encoding); + if (result == ParsingResult.Success) + { + _requestUriString.Append(_cookedUriQuery); + + Debug.Assert(_rawOctets.Count == 0, + "Still raw octets left. They must be added to the result path."); + + if (!Uri.TryCreate(_requestUriString.ToString(), UriKind.Absolute, out _requestUri)) + { + // If we can't create a Uri from the string, this is an invalid string and it doesn't make + // sense to try another encoding. + result = ParsingResult.InvalidString; + } + } + + if (result != ParsingResult.Success) + { + LogWarning("BuildRequestUriUsingRawPath", "Can't convert the raw path: " + _rawPath + " Encoding: " + encoding.WebName); + } + + return result; + } + + private ParsingResult ParseRawPath(Encoding encoding) + { + Debug.Assert(encoding != null, "'encoding' must be assigned."); + + int index = 0; + char current = '\0'; + while (index < _rawPath.Length) + { + current = _rawPath[index]; + if (current == '%') + { + // Assert is enough, since http.sys accepted the request string already. This should never happen. + Debug.Assert(index + 2 < _rawPath.Length, "Expected >=2 characters after '%' (e.g. %2F)"); + + index++; + current = _rawPath[index]; + if (current == 'u' || current == 'U') + { + // We found "%u" which means, we have a Unicode code point of the form "%uXXXX". + Debug.Assert(index + 4 < _rawPath.Length, "Expected >=4 characters after '%u' (e.g. %u0062)"); + + // Decode the content of rawOctets into percent encoded UTF-8 characters and append them + // to requestUriString. + if (!EmptyDecodeAndAppendRawOctetsList(encoding)) + { + return ParsingResult.EncodingError; + } + if (!AppendUnicodeCodePointValuePercentEncoded(_rawPath.Substring(index + 1, 4))) + { + return ParsingResult.InvalidString; + } + index += 5; + } + else + { + // We found '%', but not followed by 'u', i.e. we have a percent encoded octed: %XX + if (!AddPercentEncodedOctetToRawOctetsList(encoding, _rawPath.Substring(index, 2))) + { + return ParsingResult.InvalidString; + } + index += 2; + } + } + else + { + // We found a non-'%' character: decode the content of rawOctets into percent encoded + // UTF-8 characters and append it to the result. + if (!EmptyDecodeAndAppendRawOctetsList(encoding)) + { + return ParsingResult.EncodingError; + } + // Append the current character to the result. + _requestUriString.Append(current); + index++; + } + } + + // if the raw path ends with a sequence of percent encoded octets, make sure those get added to the + // result (requestUriString). + if (!EmptyDecodeAndAppendRawOctetsList(encoding)) + { + return ParsingResult.EncodingError; + } + + return ParsingResult.Success; + } + + private bool AppendUnicodeCodePointValuePercentEncoded(string codePoint) + { + // http.sys only supports %uXXXX (4 hex-digits), even though unicode code points could have up to + // 6 hex digits. Therefore we parse always 4 characters after %u and convert them to an int. + int codePointValue; + if (!int.TryParse(codePoint, NumberStyles.HexNumber, null, out codePointValue)) + { + LogWarning("AppendUnicodeCodePointValuePercentEncoded", "Can't convert code point: " + codePoint); + return false; + } + + string unicodeString = null; + try + { + unicodeString = char.ConvertFromUtf32(codePointValue); + AppendOctetsPercentEncoded(_requestUriString, Utf8Encoding.GetBytes(unicodeString)); + + return true; + } + catch (ArgumentOutOfRangeException) + { + LogWarning("AppendUnicodeCodePointValuePercentEncoded", "Can't convert code point: " + codePoint); + } + catch (EncoderFallbackException e) + { + // If utf8Encoding.GetBytes() fails + LogWarning("AppendUnicodeCodePointValuePercentEncoded", "Can't convert code point: " + unicodeString, e.Message); + } + + return false; + } + + private bool AddPercentEncodedOctetToRawOctetsList(Encoding encoding, string escapedCharacter) + { + byte encodedValue; + if (!byte.TryParse(escapedCharacter, NumberStyles.HexNumber, null, out encodedValue)) + { + LogWarning("AddPercentEncodedOctetToRawOctetsList", "Can't convert code point: " + escapedCharacter); + return false; + } + + _rawOctets.Add(encodedValue); + + return true; + } + + private bool EmptyDecodeAndAppendRawOctetsList(Encoding encoding) + { + if (_rawOctets.Count == 0) + { + return true; + } + + string decodedString = null; + try + { + // If the encoding can get a string out of the byte array, this is a valid string in the + // 'encoding' encoding. + byte[] bytes = _rawOctets.ToArray(); + decodedString = encoding.GetString(bytes, 0, bytes.Length); + + if (encoding == Utf8Encoding) + { + AppendOctetsPercentEncoded(_requestUriString, bytes); + } + else + { + AppendOctetsPercentEncoded(_requestUriString, Utf8Encoding.GetBytes(decodedString)); + } + + _rawOctets.Clear(); + + return true; + } + catch (DecoderFallbackException e) + { + LogWarning("EmptyDecodeAndAppendRawOctetsList", "Can't convert bytes: " + GetOctetsAsString(_rawOctets), e.Message); + } + catch (EncoderFallbackException e) + { + // If utf8Encoding.GetBytes() fails + LogWarning("EmptyDecodeAndAppendRawOctetsList", "Can't convert bytes: " + decodedString, e.Message); + } + + return false; + } + + private static void AppendOctetsPercentEncoded(StringBuilder target, IEnumerable octets) + { + foreach (byte octet in octets) + { + target.Append('%'); + target.Append(octet.ToString("X2", CultureInfo.InvariantCulture)); + } + } + + private static string GetOctetsAsString(IEnumerable octets) + { + StringBuilder octetString = new StringBuilder(); + + bool first = true; + foreach (byte octet in octets) + { + if (first) + { + first = false; + } + else + { + octetString.Append(" "); + } + octetString.Append(octet.ToString("X2", CultureInfo.InvariantCulture)); + } + + return octetString.ToString(); + } + + private static string GetPath(string uriString) + { + Debug.Assert(uriString != null, "uriString must not be null"); + Debug.Assert(uriString.Length > 0, "uriString must not be empty"); + + int pathStartIndex = 0; + + // Perf. improvement: nearly all strings are relative Uris. So just look if the + // string starts with '/'. If so, we have a relative Uri and the path starts at position 0. + // (http.sys already trimmed leading whitespaces) + if (uriString[0] != '/') + { + // We can't check against cookedUriScheme, since http.sys allows for request http://myserver/ to + // use a request line 'GET https://myserver/' (note http vs. https). Therefore check if the + // Uri starts with either http:// or https://. + int authorityStartIndex = 0; + if (uriString.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) + { + authorityStartIndex = 7; + } + else if (uriString.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + { + authorityStartIndex = 8; + } + + if (authorityStartIndex > 0) + { + // we have an absolute Uri. Find out where the authority ends and the path begins. + // Note that Uris like "http://server?query=value/1/2" are invalid according to RFC2616 + // and http.sys behavior: If the Uri contains a query, there must be at least one '/' + // between the authority and the '?' character: It's safe to just look for the first + // '/' after the authority to determine the beginning of the path. + pathStartIndex = uriString.IndexOf('/', authorityStartIndex); + if (pathStartIndex == -1) + { + // e.g. for request lines like: 'GET http://myserver' (no final '/') + pathStartIndex = uriString.Length; + } + } + else + { + // RFC2616: Request-URI = "*" | absoluteURI | abs_path | authority + // 'authority' can only be used with CONNECT which is never received by HttpListener. + // I.e. if we don't have an absolute path (must start with '/') and we don't have + // an absolute Uri (must start with http:// or https://), then 'uriString' must be '*'. + Debug.Assert((uriString.Length == 1) && (uriString[0] == '*'), "Unknown request Uri string format; " + + "Request Uri string is not an absolute Uri, absolute path, or '*': " + uriString); + + // Should we ever get here, be consistent with 2.0/3.5 behavior: just add an initial + // slash to the string and treat it as a path: + uriString = "/" + uriString; + } + } + + // Find end of path: The path is terminated by + // - the first '?' character + // - the first '#' character: This is never the case here, since http.sys won't accept + // Uris containing fragments. Also, RFC2616 doesn't allow fragments in request Uris. + // - end of Uri string + int queryIndex = uriString.IndexOf('?'); + if (queryIndex == -1) + { + queryIndex = uriString.Length; + } + + // will always return a != null string. + return AddSlashToAsteriskOnlyPath(uriString.Substring(pathStartIndex, queryIndex - pathStartIndex)); + } + + private static string AddSlashToAsteriskOnlyPath(string path) + { + Debug.Assert(path != null, "'path' must not be null"); + + // If a request like "OPTIONS * HTTP/1.1" is sent to the listener, then the request Uri + // should be "http[s]://server[:port]/*" to be compatible with pre-4.0 behavior. + if ((path.Length == 1) && (path[0] == '*')) + { + return "/*"; + } + + return path; + } + + private void LogWarning(string methodName, string message, params object[] args) + { + // TODO: Verbose log + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs new file mode 100644 index 0000000000..d25af63ed7 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs @@ -0,0 +1,756 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal sealed unsafe class Response : IDisposable + { + private ResponseState _responseState; + private IDictionary _headers; + private ResponseStream _responseStream; + private long _contentLength; + private BoundaryType _boundaryType; + private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE _nativeResponse; + private IList, object>> _onSendingHeadersActions; + + private RequestContext _requestContext; + + internal Response(RequestContext httpContext) + { + // TODO: Verbose log + _requestContext = httpContext; + _nativeResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE(); + _headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + _boundaryType = BoundaryType.None; + _nativeResponse.StatusCode = (ushort)HttpStatusCode.OK; + _nativeResponse.Version.MajorVersion = 1; + _nativeResponse.Version.MinorVersion = 1; + _responseState = ResponseState.Created; + _onSendingHeadersActions = new List, object>>(); + } + + private enum ResponseState + { + Created, + ComputedHeaders, + SentHeaders, + Closed, + } + + private RequestContext RequestContext + { + get + { + return _requestContext; + } + } + + private Request Request + { + get + { + return RequestContext.Request; + } + } + + internal Stream OutputStream + { + get + { + CheckDisposed(); + EnsureResponseStream(); + return _responseStream; + } + } + + internal int GetStatusCode() + { + int statusCode = _requestContext.Environment.ResponseStatusCode ?? 200; + if (statusCode <= 100 || statusCode > 999) + { + // TODO: Move this validation to the dictionary facade so it throws when the app sets it, rather than durring send? + throw new InvalidOperationException(string.Format(Resources.Exception_InvalidStatusCode, statusCode)); + } + return statusCode; + } + + internal string GetReasonPhrase(int statusCode) + { + // TODO: Validate user input for illegal chars, length limit, etc.? + string reasonPhrase = _requestContext.Environment.ResponseReasonPhrase; + if (string.IsNullOrWhiteSpace(reasonPhrase)) + { + // if the user hasn't set this, generated on the fly, if possible. + // We know this one is safe, no need to verify it as in the setter. + reasonPhrase = HttpReasonPhrase.Get(statusCode) ?? string.Empty; + } + return reasonPhrase; + } + + // We MUST NOT send message-body when we send responses with these Status codes + private static readonly int[] NoResponseBody = { 100, 101, 204, 205, 304 }; + + private static bool CanSendResponseBody(int responseCode) + { + for (int i = 0; i < NoResponseBody.Length; i++) + { + if (responseCode == NoResponseBody[i]) + { + return false; + } + } + return true; + } + + internal EntitySendFormat EntitySendFormat + { + get + { + return (EntitySendFormat)_boundaryType; + } + } + + internal IDictionary Headers + { + get + { + return _headers; + } + } + + internal long ContentLength64 + { + get + { + return _contentLength; + } + } + + private Version GetProtocolVersion() + { + Version requestVersion = Request.ProtocolVersion; + Version responseVersion = requestVersion; + string protocolVersion = RequestContext.Environment.Get(Constants.HttpResponseProtocolKey); + + // Optional + if (!string.IsNullOrWhiteSpace(protocolVersion)) + { + if (string.Equals("HTTP/1.1", protocolVersion, StringComparison.OrdinalIgnoreCase)) + { + responseVersion = Constants.V1_1; + } + if (string.Equals("HTTP/1.0", protocolVersion, StringComparison.OrdinalIgnoreCase)) + { + responseVersion = Constants.V1_0; + } + else + { + // TODO: Just log? It's too late to get this to user code. + throw new ArgumentException(string.Empty, Constants.HttpResponseProtocolKey); + } + } + + if (requestVersion == responseVersion) + { + return requestVersion; + } + + // Return the lesser of the two versions. There are only two, so it it will always be 1.0. + return Constants.V1_0; + } + + public void Dispose() + { + Dispose(true); + } + + private void Dispose(bool disposing) + { + if (disposing) + { + if (_responseState >= ResponseState.Closed) + { + return; + } + // TODO: Verbose log + EnsureResponseStream(); + _responseStream.Dispose(); + _responseState = ResponseState.Closed; + } + } + + // old API, now private, and helper methods + + internal BoundaryType BoundaryType + { + get + { + return _boundaryType; + } + } + + internal bool SentHeaders + { + get + { + return _responseState >= ResponseState.SentHeaders; + } + } + + internal bool ComputedHeaders + { + get + { + return _responseState >= ResponseState.ComputedHeaders; + } + } + + private void EnsureResponseStream() + { + if (_responseStream == null) + { + _responseStream = new ResponseStream(RequestContext); + } + } + + /* + 12.3 + HttpSendHttpResponse() and HttpSendResponseEntityBody() Flag Values. + The following flags can be used on calls to HttpSendHttpResponse() and HttpSendResponseEntityBody() API calls: + + #define HTTP_SEND_RESPONSE_FLAG_DISCONNECT 0x00000001 + #define HTTP_SEND_RESPONSE_FLAG_MORE_DATA 0x00000002 + #define HTTP_SEND_RESPONSE_FLAG_RAW_HEADER 0x00000004 + #define HTTP_SEND_RESPONSE_FLAG_VALID 0x00000007 + + HTTP_SEND_RESPONSE_FLAG_DISCONNECT: + specifies that the network connection should be disconnected immediately after + sending the response, overriding the HTTP protocol's persistent connection features. + HTTP_SEND_RESPONSE_FLAG_MORE_DATA: + specifies that additional entity body data will be sent by the caller. Thus, + the last call HttpSendResponseEntityBody for a RequestId, will have this flag reset. + HTTP_SEND_RESPONSE_RAW_HEADER: + specifies that a caller of HttpSendResponseEntityBody() is intentionally omitting + a call to HttpSendHttpResponse() in order to bypass normal header processing. The + actual HTTP header will be generated by the application and sent as entity body. + This flag should be passed on the first call to HttpSendResponseEntityBody, and + not after. Thus, flag is not applicable to HttpSendHttpResponse. + */ + + // TODO: Consider using HTTP_SEND_RESPONSE_RAW_HEADER with HttpSendResponseEntityBody instead of calling HttpSendHttpResponse. + // This will give us more control of the bytes that hit the wire, including encodings, HTTP 1.0, etc.. + // It may also be faster to do this work in managed code and then pass down only one buffer. + // What would we loose by bypassing HttpSendHttpResponse? + // + // TODO: Consider using the HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA flag for most/all responses rather than just Opaque. + internal unsafe uint SendHeaders(UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* pDataChunk, + ResponseStreamAsyncResult asyncResult, + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags, + bool isOpaqueUpgrade) + { + Debug.Assert(!SentHeaders, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); + + // TODO: Verbose log headers + _responseState = ResponseState.SentHeaders; + + _nativeResponse.StatusCode = (ushort)GetStatusCode(); + string reasonPhrase = GetReasonPhrase(_nativeResponse.StatusCode); + + /* + if (m_BoundaryType==BoundaryType.Raw) { + use HTTP_SEND_RESPONSE_FLAG_RAW_HEADER; + } + */ + uint statusCode; + uint bytesSent; + List pinnedHeaders = SerializeHeaders(ref _nativeResponse.Headers, isOpaqueUpgrade); + try + { + if (pDataChunk != null) + { + _nativeResponse.EntityChunkCount = 1; + _nativeResponse.pEntityChunks = pDataChunk; + } + else if (asyncResult != null && asyncResult.DataChunks != null) + { + _nativeResponse.EntityChunkCount = asyncResult.DataChunkCount; + _nativeResponse.pEntityChunks = asyncResult.DataChunks; + } + else + { + _nativeResponse.EntityChunkCount = 0; + _nativeResponse.pEntityChunks = null; + } + + if (reasonPhrase.Length > 0) + { + byte[] reasonPhraseBytes = new byte[HeaderEncoding.GetByteCount(reasonPhrase)]; + fixed (byte* pReasonPhrase = reasonPhraseBytes) + { + _nativeResponse.ReasonLength = (ushort)reasonPhraseBytes.Length; + HeaderEncoding.GetBytes(reasonPhrase, 0, reasonPhraseBytes.Length, reasonPhraseBytes, 0); + _nativeResponse.pReason = (sbyte*)pReasonPhrase; + fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE* pResponse = &_nativeResponse) + { + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( + RequestContext.RequestQueueHandle, + Request.RequestId, + (uint)flags, + pResponse, + null, + &bytesSent, + SafeLocalFree.Zero, + 0, + asyncResult == null ? SafeNativeOverlapped.Zero : asyncResult.NativeOverlapped, + IntPtr.Zero); + + if (asyncResult != null && + statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + OwinWebListener.SkipIOCPCallbackOnSuccess) + { + asyncResult.BytesSent = bytesSent; + // The caller will invoke IOCompleted + } + } + } + } + else + { + fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE* pResponse = &_nativeResponse) + { + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( + RequestContext.RequestQueueHandle, + Request.RequestId, + (uint)flags, + pResponse, + null, + &bytesSent, + SafeLocalFree.Zero, + 0, + asyncResult == null ? SafeNativeOverlapped.Zero : asyncResult.NativeOverlapped, + IntPtr.Zero); + + if (asyncResult != null && + statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + OwinWebListener.SkipIOCPCallbackOnSuccess) + { + asyncResult.BytesSent = bytesSent; + // The caller will invoke IOCompleted + } + } + } + } + finally + { + FreePinnedHeaders(pinnedHeaders); + } + return statusCode; + } + + internal UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS ComputeHeaders(bool endOfRequest = false) + { + // Notify that this is absolutely the last chance to make changes. + NotifyOnSendingHeaders(); + + // 401 + if (GetStatusCode() == (ushort)HttpStatusCode.Unauthorized) + { + RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(this); + } + + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + Debug.Assert(!ComputedHeaders, "HttpListenerResponse::ComputeHeaders()|ComputedHeaders is true."); + _responseState = ResponseState.ComputedHeaders; + /* + // here we would check for BoundaryType.Raw, in this case we wouldn't need to do anything + if (m_BoundaryType==BoundaryType.Raw) { + return flags; + } + */ + + // Check the response headers to determine the correct keep alive and boundary type. + Version responseVersion = GetProtocolVersion(); + _nativeResponse.Version.MajorVersion = (ushort)responseVersion.Major; + _nativeResponse.Version.MinorVersion = (ushort)responseVersion.Minor; + bool keepAlive = responseVersion >= Constants.V1_1; + string connectionString = Headers.Get(HttpKnownHeaderNames.Connection); + string keepAliveString = Headers.Get(HttpKnownHeaderNames.KeepAlive); + bool closeSet = false; + bool keepAliveSet = false; + + if (!string.IsNullOrWhiteSpace(connectionString) && string.Equals("close", connectionString.Trim(), StringComparison.OrdinalIgnoreCase)) + { + keepAlive = false; + closeSet = true; + } + else if (!string.IsNullOrWhiteSpace(keepAliveString) && string.Equals("true", keepAliveString.Trim(), StringComparison.OrdinalIgnoreCase)) + { + keepAlive = true; + keepAliveSet = true; + } + + // Content-Length takes priority + string contentLengthString = Headers.Get(HttpKnownHeaderNames.ContentLength); + string transferEncodingString = Headers.Get(HttpKnownHeaderNames.TransferEncoding); + + if (responseVersion == Constants.V1_0 && !string.IsNullOrEmpty(transferEncodingString) + && string.Equals("chunked", transferEncodingString.Trim(), StringComparison.OrdinalIgnoreCase)) + { + // A 1.0 client can't process chunked responses. + Headers.Remove(HttpKnownHeaderNames.TransferEncoding); + transferEncodingString = null; + } + + if (!string.IsNullOrWhiteSpace(contentLengthString)) + { + contentLengthString = contentLengthString.Trim(); + if (string.Equals("0", contentLengthString, StringComparison.Ordinal)) + { + _boundaryType = BoundaryType.ContentLength; + _contentLength = 0; + flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + } + else if (long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out _contentLength)) + { + _boundaryType = BoundaryType.ContentLength; + if (_contentLength == 0) + { + flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + } + } + else + { + _boundaryType = BoundaryType.Invalid; + } + } + else if (!string.IsNullOrWhiteSpace(transferEncodingString) + && string.Equals("chunked", transferEncodingString.Trim(), StringComparison.OrdinalIgnoreCase)) + { + // Then Transfer-Encoding: chunked + _boundaryType = BoundaryType.Chunked; + } + else if (endOfRequest) + { + // The request is ending without a body, add a Content-Length: 0 header. + Headers[HttpKnownHeaderNames.ContentLength] = new string[] { "0" }; + _boundaryType = BoundaryType.ContentLength; + _contentLength = 0; + flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + } + else + { + // Then fall back to Connection:Close transparent mode. + _boundaryType = BoundaryType.None; + flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; // seems like HTTP_SEND_RESPONSE_FLAG_MORE_DATA but this hangs the app; + if (responseVersion == Constants.V1_0) + { + keepAlive = false; + } + else + { + Headers[HttpKnownHeaderNames.TransferEncoding] = new string[] { "chunked" }; + _boundaryType = BoundaryType.Chunked; + } + + if (CanSendResponseBody(_requestContext.Response.GetStatusCode())) + { + _contentLength = -1; + } + else + { + Headers[HttpKnownHeaderNames.ContentLength] = new string[] { "0" }; + _contentLength = 0; + _boundaryType = BoundaryType.ContentLength; + } + } + + // Also, Keep-Alive vs Connection Close + + if (!keepAlive) + { + if (!closeSet) + { + Headers.Append(HttpKnownHeaderNames.Connection, "close"); + } + if (flags == UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE) + { + flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; + } + } + else + { + if (Request.ProtocolVersion.Minor == 0 && !keepAliveSet) + { + Headers[HttpKnownHeaderNames.KeepAlive] = new string[] { "true" }; + } + } + return flags; + } + + private List SerializeHeaders(ref UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADERS headers, + bool isOpaqueUpgrade) + { + UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; + List pinnedHeaders; + GCHandle gcHandle; + /* + // here we would check for BoundaryType.Raw, in this case we wouldn't need to do anything + if (m_BoundaryType==BoundaryType.Raw) { + return null; + } + */ + if (Headers.Count == 0) + { + return null; + } + string headerName; + string headerValue; + int lookup; + byte[] bytes = null; + pinnedHeaders = new List(); + + //--------------------------------------------------- + // DTS Issue: 609383: + // The Set-Cookie headers are being merged into one. + // There are two issues here. + // 1. When Set-Cookie headers are set through SetCookie method on the ListenerResponse, + // there is code in the SetCookie method and the methods it calls to flatten the Set-Cookie + // values. This blindly concatenates the cookies with a comma delimiter. There could be + // a cookie value that contains comma, but we don't escape it with %XX value + // + // As an alternative users can add the Set-Cookie header through the AddHeader method + // like ListenerResponse.Headers.Add("name", "value") + // That way they can add multiple headers - AND They can format the value like they want it. + // + // 2. Now that the header collection contains multiple Set-Cookie name, value pairs + // you would think the problem would go away. However here is an interesting thing. + // For NameValueCollection, when you add + // "Set-Cookie", "value1" + // "Set-Cookie", "value2" + // The NameValueCollection.Count == 1. Because there is only one key + // NameValueCollection.Get("Set-Cookie") would conveniently take these two values + // concatenate them with a comma like + // value1,value2. + // In order to get individual values, you need to use + // string[] values = NameValueCollection.GetValues("Set-Cookie"); + // + // ------------------------------------------------------------- + // So here is the proposed fix here. + // We must first to loop through all the NameValueCollection keys + // and if the name is a unknown header, we must compute the number of + // values it has. Then, we should allocate that many unknown header array + // elements. + // + // Note that a part of the fix here is to treat Set-Cookie as an unknown header + // + // + //----------------------------------------------------------- + int numUnknownHeaders = 0; + foreach (KeyValuePair headerPair in Headers) + { + // See if this is an unknown header + lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); + + // TODO: WWW-Authentiate header + // TODO: HTTP_RESPONSE_V2 has a HTTP_MULTIPLE_KNOWN_HEADERS option where you can supply multiple values. + + // TODO: Consider any 'known' header that has multiple values as 'unknown'? + // Treat Set-Cookie as well as Connection header in opaque mode as unknown + if (lookup == (int)HttpSysResponseHeader.SetCookie || + (isOpaqueUpgrade && lookup == (int)HttpSysResponseHeader.Connection)) + { + lookup = -1; + } + + if (lookup == -1) + { + numUnknownHeaders += headerPair.Value.Length; + } + } + + try + { + fixed (UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER* pKnownHeaders = &headers.KnownHeaders) + { + foreach (KeyValuePair headerPair in Headers) + { + headerName = headerPair.Key; + lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); + if (lookup == (int)HttpSysResponseHeader.SetCookie || + (isOpaqueUpgrade && lookup == (int)HttpSysResponseHeader.Connection)) + { + lookup = -1; + } + + if (lookup == -1) + { + if (unknownHeaders == null) + { + //---------------------------------------- + // *** This following comment is no longer true *** + // we waste some memory here (up to 32*41=1312 bytes) but we gain speed + // unknownHeaders = new UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[Headers.Count-index]; + //-------------------------------------------- + unknownHeaders = new UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[numUnknownHeaders]; + gcHandle = GCHandle.Alloc(unknownHeaders, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + headers.pUnknownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + } + + //---------------------------------------- + // FOR UNKNOWN HEADERS + // ALLOW MULTIPLE HEADERS to be added + //--------------------------------------- + string[] headerValues = headerPair.Value; + for (int headerValueIndex = 0; headerValueIndex < headerValues.Length; headerValueIndex++) + { + // Add Name + bytes = new byte[HeaderEncoding.GetByteCount(headerName)]; + unknownHeaders[headers.UnknownHeaderCount].NameLength = (ushort)bytes.Length; + HeaderEncoding.GetBytes(headerName, 0, bytes.Length, bytes, 0); + gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + unknownHeaders[headers.UnknownHeaderCount].pName = (sbyte*)gcHandle.AddrOfPinnedObject(); + + // Add Value + headerValue = headerValues[headerValueIndex]; + bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + unknownHeaders[headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length; + HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); + gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + unknownHeaders[headers.UnknownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + headers.UnknownHeaderCount++; + } + } + else + { + string[] headerValues = headerPair.Value; + headerValue = headerValues.Length == 1 ? headerValues[0] : string.Join(", ", headerValues); + if (headerValue != null) + { + bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + pKnownHeaders[lookup].RawValueLength = (ushort)bytes.Length; + HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); + gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + pKnownHeaders[lookup].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + } + } + } + } + } + catch + { + FreePinnedHeaders(pinnedHeaders); + throw; + } + return pinnedHeaders; + } + + private static void FreePinnedHeaders(List pinnedHeaders) + { + if (pinnedHeaders != null) + { + foreach (GCHandle gcHandle in pinnedHeaders) + { + if (gcHandle.IsAllocated) + { + gcHandle.Free(); + } + } + } + } + + // Subset of ComputeHeaders + internal void SendOpaqueUpgrade() + { + // TODO: Should we do this notification earlier when you still have a chance to change the status code to avoid an upgrade? + // Notify that this is absolutely the last chance to make changes. + NotifyOnSendingHeaders(); + + // TODO: Send headers async? + ulong errorCode = SendHeaders(null, null, + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE | + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA | + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA, + true); + + if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new WebListenerException((int)errorCode); + } + } + + private void CheckDisposed() + { + if (_responseState >= ResponseState.Closed) + { + throw new ObjectDisposedException(this.GetType().FullName); + } + } + + internal void CancelLastWrite(SafeHandle requestQueueHandle) + { + if (_responseStream != null) + { + _responseStream.CancelLastWrite(requestQueueHandle); + } + } + + internal Task SendFileAsync(string fileName, long offset, long? count, CancellationToken cancel) + { + EnsureResponseStream(); + return _responseStream.SendFileAsync(fileName, offset, count, cancel); + } + + internal void SwitchToOpaqueMode() + { + EnsureResponseStream(); + _responseStream.SwitchToOpaqueMode(); + } + + internal void RegisterForOnSendingHeaders(Action callback, object state) + { + IList, object>> actions = _onSendingHeadersActions; + if (actions == null) + { + throw new InvalidOperationException("Headers already sent"); + } + + actions.Add(new Tuple, object>(callback, state)); + } + + private void NotifyOnSendingHeaders() + { + var actions = Interlocked.Exchange(ref _onSendingHeadersActions, null); + if (actions == null) + { + // Something threw the first time, do not try again. + return; + } + + // Execute last to first. This mimics a stack unwind. + foreach (var actionPair in actions.Reverse()) + { + actionPair.Item1(actionPair.Item2); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs new file mode 100644 index 0000000000..0177312901 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs @@ -0,0 +1,826 @@ +// ------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class ResponseStream : Stream + { + private static readonly byte[] ChunkTerminator = new byte[] { (byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }; + + private RequestContext _requestContext; + private long _leftToWrite = long.MinValue; + private bool _closed; + private bool _inOpaqueMode; + // The last write needs special handling to cancel. + private ResponseStreamAsyncResult _lastWrite; + + internal ResponseStream(RequestContext requestContext) + { + _requestContext = requestContext; + } + + public override bool CanSeek + { + get + { + return false; + } + } + + public override bool CanWrite + { + get + { + return true; + } + } + + public override bool CanRead + { + get + { + return false; + } + } + + public override long Length + { + get + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + } + + public override long Position + { + get + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + set + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + } + + // Send headers + public override void Flush() + { + if (_closed || _requestContext.Response.SentHeaders) + { + return; + } + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); + // TODO: Verbose log + + try + { + uint statusCode; + unsafe + { + flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + statusCode = _requestContext.Response.SendHeaders(null, null, flags, false); + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + throw new WebListenerException((int)statusCode); + } + } + catch (Exception e) + { + LogHelper.LogException(_requestContext.Logger, "Flush", e); + _closed = true; + _requestContext.Abort(); + throw; + } + } + + // Send headers + public override Task FlushAsync(CancellationToken cancellationToken) + { + if (_closed || _requestContext.Response.SentHeaders) + { + return Helpers.CompletedTask(); + } + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); + // TODO: Verbose log + + // TODO: Real cancellation + cancellationToken.ThrowIfCancellationRequested(); + + flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, null, 0, 0, _requestContext.Response.BoundaryType == BoundaryType.Chunked, false); + + try + { + uint statusCode; + unsafe + { + statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); + } + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.IOCompleted(statusCode); + } + else if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + throw new WebListenerException((int)statusCode); + } + } + catch (Exception e) + { + LogHelper.LogException(_requestContext.Logger, "FlushAsync", e); + asyncResult.Dispose(); + _closed = true; + _requestContext.Abort(); + throw; + } + + return asyncResult.Task; + } + + #region NotSupported Read/Seek + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(Resources.Exception_NoSeek); + } + + public override int Read([In, Out] byte[] buffer, int offset, int size) + { + throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); + } + +#if NET45 + public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + { + throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); + } + + public override int EndRead(IAsyncResult asyncResult) + { + throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); + } +#endif + + #endregion + + private UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS ComputeLeftToWrite(bool endOfRequest = false) + { + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + if (!_requestContext.Response.ComputedHeaders) + { + flags = _requestContext.Response.ComputeHeaders(endOfRequest: endOfRequest); + } + if (_leftToWrite == long.MinValue) + { + UnsafeNclNativeMethods.HttpApi.HTTP_VERB method = _requestContext.GetKnownMethod(); + if (method == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD) + { + _leftToWrite = 0; + } + else if (_requestContext.Response.EntitySendFormat == EntitySendFormat.ContentLength) + { + _leftToWrite = _requestContext.Response.ContentLength64; + } + else + { + _leftToWrite = -1; // unlimited + } + } + return flags; + } + + public override unsafe void Write(byte[] buffer, int offset, int size) + { + 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"); + } + if (_closed) + { + throw new ObjectDisposedException(GetType().FullName); + } + // TODO: Verbose log parameters + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); + if (size == 0 && _leftToWrite != 0) + { + return; + } + if (_leftToWrite >= 0 && size > _leftToWrite) + { + throw new InvalidOperationException(Resources.Exception_TooMuchWritten); + } + // TODO: Verbose log + + uint statusCode; + uint dataToWrite = (uint)size; + SafeLocalFree bufferAsIntPtr = null; + IntPtr pBufferAsIntPtr = IntPtr.Zero; + bool sentHeaders = _requestContext.Response.SentHeaders; + try + { + if (size == 0) + { + // TODO: Is this code path accessible? Is this like a Flush? + statusCode = _requestContext.Response.SendHeaders(null, null, flags, false); + } + else + { + fixed (byte* pDataBuffer = buffer) + { + byte* pBuffer = pDataBuffer; + if (_requestContext.Response.BoundaryType == BoundaryType.Chunked) + { + // TODO: + // here we need some heuristics, some time it is definitely better to split this in 3 write calls + // but for small writes it is probably good enough to just copy the data internally. + 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; i < chunkHeader.Length; i++) + { + Marshal.WriteByte(pBufferAsIntPtr, i, (byte)chunkHeader[i]); + } + Marshal.WriteInt16(pBufferAsIntPtr, chunkHeader.Length, 0x0A0D); + Marshal.Copy(buffer, offset, IntPtrHelper.Add(pBufferAsIntPtr, chunkHeader.Length + 2), size); + Marshal.WriteInt16(pBufferAsIntPtr, (int)(dataToWrite - 2), 0x0A0D); + pBuffer = (byte*)pBufferAsIntPtr; + offset = 0; + } + UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK dataChunk = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + dataChunk.DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + dataChunk.fromMemory.pBuffer = (IntPtr)(pBuffer + offset); + dataChunk.fromMemory.BufferLength = dataToWrite; + + flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + if (!sentHeaders) + { + statusCode = _requestContext.Response.SendHeaders(&dataChunk, null, flags, false); + } + else + { + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + (uint)flags, + 1, + &dataChunk, + null, + SafeLocalFree.Zero, + 0, + SafeNativeOverlapped.Zero, + IntPtr.Zero); + + if (_requestContext.Server.IgnoreWriteExceptions) + { + statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; + } + } + } + } + } + finally + { + if (bufferAsIntPtr != null) + { + // free unmanaged buffer + bufferAsIntPtr.Dispose(); + } + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + Exception exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_requestContext.Logger, "Write", exception); + _closed = true; + _requestContext.Abort(); + throw exception; + } + UpdateWritenCount(dataToWrite); + + // TODO: Verbose log data written + } +#if NET45 + public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#else + public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#endif + { + 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"); + } + if (_closed) + { + throw new ObjectDisposedException(GetType().FullName); + } + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); + if (size == 0 && _leftToWrite != 0) + { + ResponseStreamAsyncResult result = new ResponseStreamAsyncResult(this, state, callback); + result.Complete(); + return result; + } + if (_leftToWrite >= 0 && size > _leftToWrite) + { + throw new InvalidOperationException(Resources.Exception_TooMuchWritten); + } + // TODO: Verbose log parameters + + uint statusCode; + uint bytesSent = 0; + flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + bool sentHeaders = _requestContext.Response.SentHeaders; + ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, state, callback, buffer, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders); + + // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite. + UpdateWritenCount((uint)((_requestContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size)); + + try + { + if (!sentHeaders) + { + statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); + bytesSent = asyncResult.BytesSent; + } + else + { + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + (uint)flags, + asyncResult.DataChunkCount, + asyncResult.DataChunks, + &bytesSent, + SafeLocalFree.Zero, + 0, + asyncResult.NativeOverlapped, + IntPtr.Zero); + } + } + catch (Exception e) + { + LogHelper.LogException(_requestContext.Logger, "BeginWrite", e); + asyncResult.Dispose(); + _closed = true; + _requestContext.Abort(); + throw; + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (_requestContext.Server.IgnoreWriteExceptions && sentHeaders) + { + asyncResult.Complete(); + } + else + { + Exception exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_requestContext.Logger, "BeginWrite", exception); + _closed = true; + _requestContext.Abort(); + throw exception; + } + } + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.IOCompleted(statusCode, bytesSent); + } + + // Last write, cache it for special cancelation handling. + if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) + { + _lastWrite = asyncResult; + } + + return asyncResult; + } +#if NET45 + public override void EndWrite(IAsyncResult asyncResult) +#else + public void EndWrite(IAsyncResult asyncResult) +#endif + { + if (asyncResult == null) + { + throw new ArgumentNullException("asyncResult"); + } + ResponseStreamAsyncResult castedAsyncResult = asyncResult as ResponseStreamAsyncResult; + if (castedAsyncResult == null || castedAsyncResult.ResponseStream != this) + { + throw new ArgumentException(Resources.Exception_WrongIAsyncResult, "asyncResult"); + } + if (castedAsyncResult.EndCalled) + { + throw new InvalidOperationException(Resources.Exception_EndCalledMultipleTimes); + } + castedAsyncResult.EndCalled = true; + + try + { + // wait & then check for errors + // TODO: Gracefull re-throw + castedAsyncResult.Task.Wait(); + } + catch (Exception exception) + { + LogHelper.LogException(_requestContext.Logger, "EndWrite", exception); + _closed = true; + _requestContext.Abort(); + throw; + } + } + + public override unsafe Task WriteAsync(byte[] buffer, int offset, int size, CancellationToken cancel) + { + 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"); + } + if (_closed) + { + throw new ObjectDisposedException(GetType().FullName); + } + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); + if (size == 0 && _leftToWrite != 0) + { + return Helpers.CompletedTask(); + } + if (_leftToWrite >= 0 && size > _leftToWrite) + { + throw new InvalidOperationException(Resources.Exception_TooMuchWritten); + } + // TODO: Verbose log + + // TODO: Real cancelation + cancel.ThrowIfCancellationRequested(); + + uint statusCode; + uint bytesSent = 0; + flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + bool sentHeaders = _requestContext.Response.SentHeaders; + ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, buffer, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders); + + // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite. + UpdateWritenCount((uint)((_requestContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size)); + + try + { + if (!sentHeaders) + { + statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); + bytesSent = asyncResult.BytesSent; + } + else + { + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + (uint)flags, + asyncResult.DataChunkCount, + asyncResult.DataChunks, + &bytesSent, + SafeLocalFree.Zero, + 0, + asyncResult.NativeOverlapped, + IntPtr.Zero); + } + } + catch (Exception e) + { + LogHelper.LogException(_requestContext.Logger, "WriteAsync", e); + asyncResult.Dispose(); + _closed = true; + _requestContext.Abort(); + throw; + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (_requestContext.Server.IgnoreWriteExceptions && sentHeaders) + { + asyncResult.Complete(); + } + else + { + Exception exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_requestContext.Logger, "WriteAsync", exception); + _closed = true; + _requestContext.Abort(); + throw exception; + } + } + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.IOCompleted(statusCode, bytesSent); + } + + // Last write, cache it for special cancelation handling. + if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) + { + _lastWrite = asyncResult; + } + + return asyncResult.Task; + } + + internal unsafe Task SendFileAsync(string fileName, long offset, long? size, CancellationToken cancel) + { + // It's too expensive to validate the file attributes before opening the file. Open the file and then check the lengths. + // This all happens inside of ResponseStreamAsyncResult. + if (string.IsNullOrWhiteSpace(fileName)) + { + throw new ArgumentNullException("fileName"); + } + if (_closed) + { + throw new ObjectDisposedException(GetType().FullName); + } + + // TODO: Real cancellation + cancel.ThrowIfCancellationRequested(); + + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); + if (size == 0 && _leftToWrite != 0) + { + return Helpers.CompletedTask(); + } + if (_leftToWrite >= 0 && size > _leftToWrite) + { + throw new InvalidOperationException(Resources.Exception_TooMuchWritten); + } + // TODO: Verbose log + + uint statusCode; + uint bytesSent = 0; + flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + bool sentHeaders = _requestContext.Response.SentHeaders; + ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, fileName, offset, size, + _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders); + + long bytesWritten; + if (_requestContext.Response.BoundaryType == BoundaryType.Chunked) + { + bytesWritten = 0; + } + else if (size.HasValue) + { + bytesWritten = size.Value; + } + else + { + bytesWritten = asyncResult.FileLength - offset; + } + // Update m_LeftToWrite now so we can queue up additional calls to SendFileAsync. + UpdateWritenCount((uint)bytesWritten); + + try + { + if (!sentHeaders) + { + statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); + bytesSent = asyncResult.BytesSent; + } + else + { + // TODO: If opaque then include the buffer data flag. + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + (uint)flags, + asyncResult.DataChunkCount, + asyncResult.DataChunks, + &bytesSent, + SafeLocalFree.Zero, + 0, + asyncResult.NativeOverlapped, + IntPtr.Zero); + } + } + catch (Exception e) + { + LogHelper.LogException(_requestContext.Logger, "SendFileAsync", e); + asyncResult.Dispose(); + _closed = true; + _requestContext.Abort(); + throw; + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (_requestContext.Server.IgnoreWriteExceptions && sentHeaders) + { + asyncResult.Complete(); + } + else + { + Exception exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_requestContext.Logger, "SendFileAsync", exception); + _closed = true; + _requestContext.Abort(); + throw exception; + } + } + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.IOCompleted(statusCode, bytesSent); + } + + // Last write, cache it for special cancellation handling. + if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) + { + _lastWrite = asyncResult; + } + + return asyncResult.Task; + } + + private void UpdateWritenCount(uint dataWritten) + { + if (!_inOpaqueMode) + { + if (_leftToWrite > 0) + { + // keep track of the data transferred + _leftToWrite -= dataWritten; + } + if (_leftToWrite == 0) + { + // in this case we already passed 0 as the flag, so we don't need to call HttpSendResponseEntityBody() when we Close() + _closed = true; + } + } + } + + protected override unsafe void Dispose(bool disposing) + { + try + { + if (disposing) + { + if (_closed) + { + return; + } + _closed = true; + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(endOfRequest: true); + if (_leftToWrite > 0 && !_inOpaqueMode) + { + _requestContext.Abort(); + // TODO: Reduce this to a logged warning, it is thrown too late to be visible in user code. + LogHelper.LogError(_requestContext.Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length."); + return; + } + bool sentHeaders = _requestContext.Response.SentHeaders; + if (sentHeaders && _leftToWrite == 0) + { + return; + } + + uint statusCode = 0; + if ((_requestContext.Response.BoundaryType == BoundaryType.Chunked || _requestContext.Response.BoundaryType == BoundaryType.None) && (String.Compare(_requestContext.Request.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase) != 0)) + { + if (_requestContext.Response.BoundaryType == BoundaryType.None) + { + flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; + } + fixed (void* pBuffer = ChunkTerminator) + { + UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* pDataChunk = null; + if (_requestContext.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.fromMemory.pBuffer = (IntPtr)pBuffer; + dataChunk.fromMemory.BufferLength = (uint)ChunkTerminator.Length; + pDataChunk = &dataChunk; + } + if (!sentHeaders) + { + statusCode = _requestContext.Response.SendHeaders(pDataChunk, null, flags, false); + } + else + { + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + (uint)flags, + pDataChunk != null ? (ushort)1 : (ushort)0, + pDataChunk, + null, + SafeLocalFree.Zero, + 0, + SafeNativeOverlapped.Zero, + IntPtr.Zero); + + if (_requestContext.Server.IgnoreWriteExceptions) + { + statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; + } + } + } + } + else + { + if (!sentHeaders) + { + statusCode = _requestContext.Response.SendHeaders(null, null, flags, false); + } + } + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF + // Don't throw for disconnects, we were already finished with the response. + && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID) + { + Exception exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_requestContext.Logger, "Dispose", exception); + _requestContext.Abort(); + throw exception; + } + _leftToWrite = 0; + } + } + finally + { + base.Dispose(disposing); + } + } + + internal void SwitchToOpaqueMode() + { + _inOpaqueMode = true; + _leftToWrite = long.MaxValue; + } + + // The final Content-Length async write can only be cancelled by CancelIoEx. + // Sync can only be cancelled by CancelSynchronousIo, but we don't attempt this right now. + [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = + "It is safe to ignore the return value on a cancel operation because the connection is being closed")] + internal unsafe void CancelLastWrite(SafeHandle requestQueueHandle) + { + ResponseStreamAsyncResult asyncState = _lastWrite; + if (asyncState != null && !asyncState.IsCompleted) + { + UnsafeNclNativeMethods.CancelIoEx(requestQueueHandle, asyncState.NativeOverlapped); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs new file mode 100644 index 0000000000..ca38ba6355 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs @@ -0,0 +1,441 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal unsafe class ResponseStreamAsyncResult : IAsyncResult, IDisposable + { + private static readonly byte[] CRLF = new byte[] { (byte)'\r', (byte)'\n' }; + private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(Callback); + + private SafeNativeOverlapped _overlapped; + private UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[] _dataChunks; + private bool _sentHeaders; + private FileStream _fileStream; + private ResponseStream _responseStream; + private TaskCompletionSource _tcs; + private AsyncCallback _callback; + private uint _bytesSent; + + internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback) + { + _responseStream = responseStream; + _tcs = new TaskCompletionSource(userState); + _callback = callback; + } + + internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback, + byte[] buffer, int offset, int size, bool chunked, bool sentHeaders) + : this(responseStream, userState, callback) + { + _sentHeaders = sentHeaders; + Overlapped overlapped = new Overlapped(); + overlapped.AsyncResult = this; + + if (size == 0) + { + _dataChunks = null; + _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, null)); + } + else + { + _dataChunks = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1]; + + object[] objectsToPin = new object[1 + _dataChunks.Length]; + objectsToPin[_dataChunks.Length] = _dataChunks; + + int chunkHeaderOffset = 0; + byte[] chunkHeaderBuffer = null; + if (chunked) + { + chunkHeaderBuffer = GetChunkHeader(size, out chunkHeaderOffset); + + _dataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + _dataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[0].fromMemory.BufferLength = (uint)(chunkHeaderBuffer.Length - chunkHeaderOffset); + + objectsToPin[0] = chunkHeaderBuffer; + + _dataChunks[1] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + _dataChunks[1].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[1].fromMemory.BufferLength = (uint)size; + + objectsToPin[1] = buffer; + + _dataChunks[2] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + _dataChunks[2].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[2].fromMemory.BufferLength = (uint)CRLF.Length; + + objectsToPin[2] = CRLF; + } + else + { + _dataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + _dataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[0].fromMemory.BufferLength = (uint)size; + + objectsToPin[0] = buffer; + } + + // This call will pin needed memory + _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, objectsToPin)); + + if (chunked) + { + _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer, chunkHeaderOffset); + _dataChunks[1].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset); + _dataChunks[2].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(CRLF, 0); + } + else + { + _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset); + } + } + } + + internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback, + string fileName, long offset, long? size, bool chunked, bool sentHeaders) + : this(responseStream, userState, callback) + { + _sentHeaders = sentHeaders; + Overlapped overlapped = new Overlapped(); + overlapped.AsyncResult = this; + + int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. +#if NET45 + // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. + _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, + FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive. +#else + _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, useAsync: true); // Extremely expensive. +#endif +#if !NET45 + throw new NotImplementedException(); +#else + long length = _fileStream.Length; // Expensive + if (offset < 0 || offset > length) + { + _fileStream.Dispose(); + throw new ArgumentOutOfRangeException("offset", offset, string.Empty); + } + if (size.HasValue && (size < 0 || size > length - offset)) + { + _fileStream.Dispose(); + throw new ArgumentOutOfRangeException("size", size, string.Empty); + } + + if (size == 0 || (!size.HasValue && _fileStream.Length == 0)) + { + _dataChunks = null; + _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, null)); + } + else + { + _dataChunks = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1]; + + object[] objectsToPin = new object[_dataChunks.Length]; + objectsToPin[_dataChunks.Length - 1] = _dataChunks; + + int chunkHeaderOffset = 0; + byte[] chunkHeaderBuffer = null; + if (chunked) + { + chunkHeaderBuffer = GetChunkHeader((int)(size ?? _fileStream.Length - offset), out chunkHeaderOffset); + + _dataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + _dataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[0].fromMemory.BufferLength = (uint)(chunkHeaderBuffer.Length - chunkHeaderOffset); + + objectsToPin[0] = chunkHeaderBuffer; + + _dataChunks[1] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + _dataChunks[1].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; + _dataChunks[1].fromFile.offset = (ulong)offset; + _dataChunks[1].fromFile.count = (ulong)(size ?? -1); + _dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); + // Nothing to pin for the file handle. + + _dataChunks[2] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + _dataChunks[2].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[2].fromMemory.BufferLength = (uint)CRLF.Length; + + objectsToPin[1] = CRLF; + } + else + { + _dataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + _dataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; + _dataChunks[0].fromFile.offset = (ulong)offset; + _dataChunks[0].fromFile.count = (ulong)(size ?? -1); + _dataChunks[0].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); + } + + // This call will pin needed memory + _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, objectsToPin)); + + if (chunked) + { + _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer, chunkHeaderOffset); + _dataChunks[2].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(CRLF, 0); + } + } +#endif + } + + internal ResponseStream ResponseStream + { + get { return _responseStream; } + } + + internal SafeNativeOverlapped NativeOverlapped + { + get { return _overlapped; } + } + + internal Task Task + { + get { return _tcs.Task; } + } + + internal uint BytesSent + { + get { return _bytesSent; } + set { _bytesSent = value; } + } + + internal ushort DataChunkCount + { + get + { + if (_dataChunks == null) + { + return 0; + } + else + { + return (ushort)_dataChunks.Length; + } + } + } + + internal UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* DataChunks + { + get + { + if (_dataChunks == null) + { + return null; + } + else + { + return (UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK*)(Marshal.UnsafeAddrOfPinnedArrayElement(_dataChunks, 0)); + } + } + } + + internal long FileLength + { + get { return _fileStream == null ? 0 : _fileStream.Length; } + } + + internal bool EndCalled { get; set; } + + internal void IOCompleted(uint errorCode) + { + IOCompleted(this, errorCode, BytesSent); + } + + internal void IOCompleted(uint errorCode, uint numBytes) + { + IOCompleted(this, errorCode, numBytes); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting to callback")] + private static void IOCompleted(ResponseStreamAsyncResult asyncResult, uint errorCode, uint numBytes) + { + try + { + if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + asyncResult.Fail(new WebListenerException((int)errorCode)); + } + else + { + if (asyncResult._dataChunks == null) + { + // TODO: Verbose log data written + } + else + { + // TODO: Verbose log + // for (int i = 0; i < asyncResult._dataChunks.Length; i++) + // { + // Logging.Dump(Logging.HttpListener, asyncResult, "Callback", (IntPtr)asyncResult._dataChunks[0].fromMemory.pBuffer, (int)asyncResult._dataChunks[0].fromMemory.BufferLength); + // } + } + asyncResult.Complete(); + } + } + catch (Exception e) + { + asyncResult.Fail(e); + } + } + + private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) + { + Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); + ResponseStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as ResponseStreamAsyncResult; + + IOCompleted(asyncResult, errorCode, numBytes); + } + + internal void Complete() + { + if (_tcs.TrySetResult(null) && _callback != null) + { + try + { + _callback(this); + } + catch (Exception) + { + // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. + // TODO: Log + } + } + Dispose(); + } + + internal void Fail(Exception ex) + { + if (_tcs.TrySetException(ex) && _callback != null) + { + try + { + _callback(this); + } + catch (Exception) + { + // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. + } + } + Dispose(); + } + + /*++ + + GetChunkHeader + + A private utility routine to convert an integer to a chunk header, + which is an ASCII hex number followed by a CRLF. The header is retuned + as a byte array. + + Input: + + size - Chunk size to be encoded + offset - Out parameter where we store offset into buffer. + + Returns: + + A byte array with the header in int. + + --*/ + + private static byte[] GetChunkHeader(int size, out int offset) + { + uint mask = 0xf0000000; + byte[] header = new byte[10]; + int i; + offset = -1; + + // Loop through the size, looking at each nibble. If it's not 0 + // convert it to hex. Save the index of the first non-zero + // byte. + + for (i = 0; i < 8; i++, size <<= 4) + { + // offset == -1 means that we haven't found a non-zero nibble + // yet. If we haven't found one, and the current one is zero, + // don't do anything. + + if (offset == -1) + { + if ((size & mask) == 0) + { + continue; + } + } + + // Either we have a non-zero nibble or we're no longer skipping + // leading zeros. Convert this nibble to ASCII and save it. + + uint temp = (uint)size >> 28; + + if (temp < 10) + { + header[i] = (byte)(temp + '0'); + } + else + { + header[i] = (byte)((temp - 10) + 'A'); + } + + // If we haven't found a non-zero nibble yet, we've found one + // now, so remember that. + + if (offset == -1) + { + offset = i; + } + } + + header[8] = (byte)'\r'; + header[9] = (byte)'\n'; + + return header; + } + + public object AsyncState + { + get { return _tcs.Task.AsyncState; } + } + + public WaitHandle AsyncWaitHandle + { + get { return ((IAsyncResult)_tcs.Task).AsyncWaitHandle; } + } + + public bool CompletedSynchronously + { + get { return ((IAsyncResult)_tcs.Task).CompletedSynchronously; } + } + + public bool IsCompleted + { + get { return _tcs.Task.IsCompleted; } + } + + public void Dispose() + { + if (_overlapped != null) + { + _overlapped.Dispose(); + } + if (_fileStream != null) + { + _fileStream.Dispose(); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/SslStatus.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/SslStatus.cs new file mode 100644 index 0000000000..72118c2d46 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/SslStatus.cs @@ -0,0 +1,15 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace Microsoft.AspNet.Server.WebListener +{ + internal enum SslStatus : byte + { + Insecure, + NoClientCert, + ClientCert + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/Resources.Designer.cs b/src/Microsoft.AspNet.Server.WebListener/Resources.Designer.cs new file mode 100644 index 0000000000..aafe87fb8d --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/Resources.Designer.cs @@ -0,0 +1,153 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34006 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.Server.WebListener { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNet.Server.WebListener.Resources", System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Resources)).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to The destination array is too small.. + /// + internal static string Exception_ArrayTooSmall { + get { + return ResourceManager.GetString("Exception_ArrayTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to End has already been called.. + /// + internal static string Exception_EndCalledMultipleTimes { + get { + return ResourceManager.GetString("Exception_EndCalledMultipleTimes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The status code '{0}' is not supported.. + /// + internal static string Exception_InvalidStatusCode { + get { + return ResourceManager.GetString("Exception_InvalidStatusCode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The stream is not seekable.. + /// + internal static string Exception_NoSeek { + get { + return ResourceManager.GetString("Exception_NoSeek", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The prefix '{0}' is already registered.. + /// + internal static string Exception_PrefixAlreadyRegistered { + get { + return ResourceManager.GetString("Exception_PrefixAlreadyRegistered", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This stream only supports read operations.. + /// + internal static string Exception_ReadOnlyStream { + get { + return ResourceManager.GetString("Exception_ReadOnlyStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to More data written than specified in the Content-Length header.. + /// + internal static string Exception_TooMuchWritten { + get { + return ResourceManager.GetString("Exception_TooMuchWritten", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only the http and https schemes are supported.. + /// + internal static string Exception_UnsupportedScheme { + get { + return ResourceManager.GetString("Exception_UnsupportedScheme", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This stream only supports write operations.. + /// + internal static string Exception_WriteOnlyStream { + get { + return ResourceManager.GetString("Exception_WriteOnlyStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The given IAsyncResult does not match this opperation.. + /// + internal static string Exception_WrongIAsyncResult { + get { + return ResourceManager.GetString("Exception_WrongIAsyncResult", resourceCulture); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/Resources.resx b/src/Microsoft.AspNet.Server.WebListener/Resources.resx new file mode 100644 index 0000000000..005bafca2f --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/Resources.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The destination array is too small. + + + End has already been called. + + + The status code '{0}' is not supported. + + + The stream is not seekable. + + + The prefix '{0}' is already registered. + + + This stream only supports read operations. + + + More data written than specified in the Content-Length header. + + + Only the http and https schemes are supported. + + + This stream only supports write operations. + + + The given IAsyncResult does not match this opperation. + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/TimeoutManager.cs b/src/Microsoft.AspNet.Server.WebListener/TimeoutManager.cs new file mode 100644 index 0000000000..9e74f6563a --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/TimeoutManager.cs @@ -0,0 +1,267 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Server.WebListener +{ + // See the native HTTP_TIMEOUT_LIMIT_INFO structure documentation for additional information. + // http://msdn.microsoft.com/en-us/library/aa364661.aspx + + /// + /// Exposes the Http.Sys timeout configurations. These may also be configured in the registry. + /// + public sealed class TimeoutManager + { +#if NET45 + private static readonly int TimeoutLimitSize = + Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO)); +#else + private static readonly int TimeoutLimitSize = + Marshal.SizeOf(); +#endif + private OwinWebListener _server; + private int[] _timeouts; + private uint _minSendBytesPerSecond; + + internal TimeoutManager(OwinWebListener context) + { + _server = context; + + // We have to maintain local state since we allow applications to set individual timeouts. Native Http + // API for setting timeouts expects all timeout values in every call so we have remember timeout values + // to fill in the blanks. Except MinSendBytesPerSecond, local state for remaining five timeouts is + // maintained in timeouts array. + // + // No initialization is required because a value of zero indicates that system defaults should be used. + _timeouts = new int[5]; + + LoadConfigurationSettings(); + } + + #region Properties + + /// + /// The time, in seconds, allowed for the request entity body to arrive. The default timer is 2 minutes. + /// + /// The HTTP Server API turns on this timer when the request has an entity body. The timer expiration is + /// initially set to the configured value. When the HTTP Server API receives additional data indications on the + /// request, it resets the timer to give the connection another interval. + /// + /// Use TimeSpan.Zero to indicate that system defaults should be used. + /// + public TimeSpan EntityBody + { + get + { + return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody); + } + set + { + SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value); + } + } + + /// + /// The time, in seconds, allowed for the HTTP Server API to drain the entity body on a Keep-Alive connection. + /// The default timer is 2 minutes. + /// + /// On a Keep-Alive connection, after the application has sent a response for a request and before the request + /// entity body has completely arrived, the HTTP Server API starts draining the remainder of the entity body to + /// reach another potentially pipelined request from the client. If the time to drain the remaining entity body + /// exceeds the allowed period the connection is timed out. + /// + /// Use TimeSpan.Zero to indicate that system defaults should be used. + /// + public TimeSpan DrainEntityBody + { + get + { + return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody); + } + set + { + SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value); + } + } + + /// + /// The time, in seconds, allowed for the request to remain in the request queue before the application picks + /// it up. The default timer is 2 minutes. + /// + /// Use TimeSpan.Zero to indicate that system defaults should be used. + /// + public TimeSpan RequestQueue + { + get + { + return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue); + } + set + { + SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value); + } + } + + /// + /// The time, in seconds, allowed for an idle connection. The default timer is 2 minutes. + /// + /// This timeout is only enforced after the first request on the connection is routed to the application. + /// + /// Use TimeSpan.Zero to indicate that system defaults should be used. + /// + public TimeSpan IdleConnection + { + get + { + return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection); + } + set + { + SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value); + } + } + + /// + /// The time, in seconds, allowed for the HTTP Server API to parse the request header. The default timer is + /// 2 minutes. + /// + /// This timeout is only enforced after the first request on the connection is routed to the application. + /// + /// Use TimeSpan.Zero to indicate that system defaults should be used. + /// + public TimeSpan HeaderWait + { + get + { + return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait); + } + set + { + SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value); + } + } + + /// + /// The minimum send rate, in bytes-per-second, for the response. The default response send rate is 150 + /// bytes-per-second. + /// + /// To disable this timer set it to UInt32.MaxValue + /// + public long MinSendBytesPerSecond + { + get + { + // Since we maintain local state, GET is local. + return _minSendBytesPerSecond; + } + set + { + // MinSendRate value is ULONG in native layer. + if (value < 0 || value > uint.MaxValue) + { + throw new ArgumentOutOfRangeException("value"); + } + + SetServerTimeout(_timeouts, (uint)value); + _minSendBytesPerSecond = (uint)value; + } + } + + #endregion Properties + + // Initial values come from the config. The values can then be overridden using this public API. + private void LoadConfigurationSettings() + { + long[] configTimeouts = new long[_timeouts.Length + 1]; // SettingsSectionInternal.Section.HttpListenerTimeouts; + Debug.Assert(configTimeouts != null); + Debug.Assert(configTimeouts.Length == (_timeouts.Length + 1)); + + bool setNonDefaults = false; + for (int i = 0; i < _timeouts.Length; i++) + { + if (configTimeouts[i] != 0) + { + Debug.Assert(configTimeouts[i] <= ushort.MaxValue, "Timeout out of range: " + configTimeouts[i]); + _timeouts[i] = (int)configTimeouts[i]; + setNonDefaults = true; + } + } + + if (configTimeouts[5] != 0) + { + Debug.Assert(configTimeouts[5] <= uint.MaxValue, "Timeout out of range: " + configTimeouts[5]); + _minSendBytesPerSecond = (uint)configTimeouts[5]; + setNonDefaults = true; + } + + if (setNonDefaults) + { + SetServerTimeout(_timeouts, _minSendBytesPerSecond); + } + } + + #region Helpers + + private TimeSpan GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type) + { + // Since we maintain local state, GET is local. + return new TimeSpan(0, 0, (int)_timeouts[(int)type]); + } + + private void SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value) + { + Int64 timeoutValue; + + // All timeouts are defined as USHORT in native layer (except MinSendRate, which is ULONG). Make sure that + // timeout value is within range. + + timeoutValue = Convert.ToInt64(value.TotalSeconds); + + if (timeoutValue < 0 || timeoutValue > ushort.MaxValue) + { + throw new ArgumentOutOfRangeException("value"); + } + + // Use local state to get values for other timeouts. Call into the native layer and if that + // call succeeds, update local state. + + int[] currentTimeouts = _timeouts; + currentTimeouts[(int)type] = (int)timeoutValue; + SetServerTimeout(currentTimeouts, _minSendBytesPerSecond); + _timeouts[(int)type] = (int)timeoutValue; + } + + private unsafe void SetServerTimeout(int[] timeouts, uint minSendBytesPerSecond) + { + UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO timeoutinfo = + new UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO(); + + timeoutinfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + timeoutinfo.DrainEntityBody = + (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody]; + timeoutinfo.EntityBody = + (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody]; + timeoutinfo.RequestQueue = + (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue]; + timeoutinfo.IdleConnection = + (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection]; + timeoutinfo.HeaderWait = + (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait]; + timeoutinfo.MinSendRate = minSendBytesPerSecond; + + IntPtr infoptr = new IntPtr(&timeoutinfo); + + _server.SetUrlGroupProperty( + UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty, + infoptr, (uint)TimeoutLimitSize); + } + + #endregion Helpers + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/ValidationHelper.cs b/src/Microsoft.AspNet.Server.WebListener/ValidationHelper.cs new file mode 100644 index 0000000000..104e49e320 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/ValidationHelper.cs @@ -0,0 +1,67 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Globalization; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal static class ValidationHelper + { + public static string ExceptionMessage(Exception exception) + { + if (exception == null) + { + return string.Empty; + } + if (exception.InnerException == null) + { + return exception.Message; + } + return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")"; + } + + public static string ToString(object objectValue) + { + if (objectValue == null) + { + return "(null)"; + } + else if (objectValue is string && ((string)objectValue).Length == 0) + { + return "(string.empty)"; + } + else if (objectValue is Exception) + { + return ExceptionMessage(objectValue as Exception); + } + else if (objectValue is IntPtr) + { + return "0x" + ((IntPtr)objectValue).ToString("x"); + } + else + { + return objectValue.ToString(); + } + } + + public static string HashString(object objectValue) + { + if (objectValue == null) + { + return "(null)"; + } + else if (objectValue is string && ((string)objectValue).Length == 0) + { + return "(string.empty)"; + } + else + { + return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs new file mode 100644 index 0000000000..19a7b78a6e --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.Server.WebListener +{ +#if NET45 + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] +#endif + internal class WebListenerException : Win32Exception + { + internal WebListenerException() + : base(Marshal.GetLastWin32Error()) + { + } + + internal WebListenerException(int errorCode) + : base(errorCode) + { + } + + internal WebListenerException(int errorCode, string message) + : base(errorCode, message) + { + } + + public override int ErrorCode + { + // the base class returns the HResult with this property + // we need the Win32 Error Code, hence the override. + + get + { + return NativeErrorCode; + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs new file mode 100644 index 0000000000..43897343aa --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -0,0 +1,32 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +#if !NET45 + +namespace Microsoft.Win32.SafeHandles +{ + using System; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + + // Class of critical handle which uses 0 or -1 as an invalid handle. + [System.Security.SecurityCritical] // auto-generated_required + internal abstract class CriticalHandleZeroOrMinusOneIsInvalid : CriticalHandle + { + protected CriticalHandleZeroOrMinusOneIsInvalid() + : base(IntPtr.Zero) + { + } + + public override bool IsInvalid + { + [System.Security.SecurityCritical] + get { return handle == new IntPtr(0) || handle == new IntPtr(-1); } + } + } +} + +#endif diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs new file mode 100644 index 0000000000..861c9e31ab --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -0,0 +1,31 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +#if !NET45 + +namespace Microsoft.Win32.SafeHandles +{ + using System; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + + // Class of safe handle which uses 0 or -1 as an invalid handle. + [System.Security.SecurityCritical] // auto-generated_required + internal abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle + { + protected SafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) + : base(IntPtr.Zero, ownsHandle) + { + } + + public override bool IsInvalid + { + [System.Security.SecurityCritical] + get { return handle == new IntPtr(0) || handle == new IntPtr(-1); } + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs new file mode 100644 index 0000000000..108303ee2c --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +#if !NET45 + +using System.Runtime.InteropServices; +using System.Text; + +namespace System.ComponentModel +{ + internal class Win32Exception : ExternalException + { + /// + /// Represents the Win32 error code associated with this exception. This + /// field is read-only. + /// + private readonly int nativeErrorCode; + + /// + /// Initializes a new instance of the class with the last Win32 error + /// that occured. + /// + public Win32Exception() + : this(Marshal.GetLastWin32Error()) + { + } + /// + /// Initializes a new instance of the class with the specified error. + /// + public Win32Exception(int error) + : this(error, GetErrorMessage(error)) + { + } + /// + /// Initializes a new instance of the class with the specified error and the + /// specified detailed description. + /// + public Win32Exception(int error, string message) + : base(message) + { + nativeErrorCode = error; + } + + /// + /// Initializes a new instance of the Exception class with a specified error message. + /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. + /// + public Win32Exception(string message) + : this(Marshal.GetLastWin32Error(), message) + { + } + + /// + /// Initializes a new instance of the Exception class with a specified error message and a + /// reference to the inner exception that is the cause of this exception. + /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. + /// + public Win32Exception(string message, Exception innerException) + : base(message, innerException) + { + nativeErrorCode = Marshal.GetLastWin32Error(); + } + + + /// + /// Represents the Win32 error code associated with this exception. This + /// field is read-only. + /// + public int NativeErrorCode + { + get + { + return nativeErrorCode; + } + } + + private static string GetErrorMessage(int error) + { + //get the system error message... + string errorMsg = ""; + StringBuilder sb = new StringBuilder(256); + int result = SafeNativeMethods.FormatMessage( + SafeNativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS | + SafeNativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | + SafeNativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY, + IntPtr.Zero, (uint)error, 0, sb, sb.Capacity + 1, + null); + if (result != 0) + { + int i = sb.Length; + while (i > 0) + { + char ch = sb[i - 1]; + if (ch > 32 && ch != '.') break; + i--; + } + errorMsg = sb.ToString(0, i); + } + else + { + errorMsg = "Unknown error (0x" + Convert.ToString(error, 16) + ")"; + } + + return errorMsg; + } + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.AspNet.Server.WebListener/fx/System/Diagnostics/TraceEventType.cs new file mode 100644 index 0000000000..36d0b93d25 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/System/Diagnostics/TraceEventType.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +#if !NET45 + +using System; +using System.ComponentModel; + +namespace System.Diagnostics +{ + internal enum TraceEventType + { + Critical = 0x01, + Error = 0x02, + Warning = 0x04, + Information = 0x08, + Verbose = 0x10, + + [EditorBrowsable(EditorBrowsableState.Advanced)] + Start = 0x0100, + [EditorBrowsable(EditorBrowsableState.Advanced)] + Stop = 0x0200, + [EditorBrowsable(EditorBrowsableState.Advanced)] + Suspend = 0x0400, + [EditorBrowsable(EditorBrowsableState.Advanced)] + Resume = 0x0800, + [EditorBrowsable(EditorBrowsableState.Advanced)] + Transfer = 0x1000, + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/ExternDll.cs b/src/Microsoft.AspNet.Server.WebListener/fx/System/ExternDll.cs new file mode 100644 index 0000000000..98303d48b8 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/System/ExternDll.cs @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +#if !NET45 + +namespace System +{ + internal static class ExternDll + { + public const string Kernel32 = "kernel32.dll"; + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.AspNet.Server.WebListener/fx/System/Runtime/InteropServices/ExternalException.cs new file mode 100644 index 0000000000..21d82b1de4 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/System/Runtime/InteropServices/ExternalException.cs @@ -0,0 +1,98 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +/*============================================================================= +** +** Class: ExternalException +** +** +** Purpose: Exception base class for all errors from Interop or Structured +** Exception Handling code. +** +** +=============================================================================*/ + +#if !NET45 + +namespace System.Runtime.InteropServices +{ + using System; + using System.Globalization; + + // Base exception for COM Interop errors &; Structured Exception Handler + // exceptions. + // + internal class ExternalException : Exception + { + public ExternalException() + { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message) + : base(message) + { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message, Exception inner) + : base(message, inner) + { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message, int errorCode) + : base(message) + { + SetErrorCode(errorCode); + } + + private void SetErrorCode(int errorCode) + { + HResult = ErrorCode; + } + + private static class __HResults + { + internal const int E_FAIL = unchecked((int)0x80004005); + } + + public virtual int ErrorCode + { + get + { + return HResult; + } + } + + public override String ToString() + { + String message = Message; + String s; + String _className = GetType().ToString(); + s = _className + " (0x" + HResult.ToString("X8", CultureInfo.InvariantCulture) + ")"; + + if (!(String.IsNullOrEmpty(message))) + { + s = s + ": " + message; + } + + Exception _innerException = InnerException; + + if (_innerException != null) + { + s = s + " ---> " + _innerException.ToString(); + } + + + if (StackTrace != null) + s += Environment.NewLine + StackTrace; + + return s; + } + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/SafeNativeMethods.cs b/src/Microsoft.AspNet.Server.WebListener/fx/System/SafeNativeMethods.cs new file mode 100644 index 0000000000..969d273fa8 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/System/SafeNativeMethods.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +#if !NET45 +using System.Runtime.InteropServices; +using System.Text; + +namespace System +{ + internal static class SafeNativeMethods + { + public const int + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; + + [DllImport(ExternDll.Kernel32, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] + public static unsafe extern int FormatMessage(int dwFlags, IntPtr lpSource_mustBeNull, uint dwMessageId, + int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr[] arguments); + + } +} +#endif diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs b/src/Microsoft.AspNet.Server.WebListener/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs new file mode 100644 index 0000000000..3c31d34a1b --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +#if !NET45 + +namespace System.Security.Authentication.ExtendedProtection +{ + internal abstract class ChannelBinding : SafeHandleZeroOrMinusOneIsInvalid + { + protected ChannelBinding() + : base(true) + { + } + + protected ChannelBinding(bool ownsHandle) + : base(ownsHandle) + { + } + + public abstract int Size + { + get; + } + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json new file mode 100644 index 0000000000..0ba47798dd --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -0,0 +1,8 @@ +{ + "version": "0.1-alpha-*", + "compilationOptions" : { "allowUnsafe": true }, + "configurations": { + "net45" : { }, + "k10" : { } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/Constants.cs b/src/Microsoft.AspNet.WebSockets/Constants.cs new file mode 100644 index 0000000000..6e9cb51ad3 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/Constants.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +namespace Microsoft.AspNet.WebSockets +{ + /// + /// Standard keys and values for use within the OWIN interfaces + /// + internal static class Constants + { + internal const string WebSocketAcceptKey = "websocket.Accept"; + internal const string WebSocketSubProtocolKey = "websocket.SubProtocol"; + internal const string WebSocketSendAsyncKey = "websocket.SendAsync"; + internal const string WebSocketReceiveAyncKey = "websocket.ReceiveAsync"; + internal const string WebSocketCloseAsyncKey = "websocket.CloseAsync"; + internal const string WebSocketCallCancelledKey = "websocket.CallCancelled"; + internal const string WebSocketVersionKey = "websocket.Version"; + internal const string WebSocketVersion = "1.0"; + internal const string WebSocketCloseStatusKey = "websocket.ClientCloseStatus"; + internal const string WebSocketCloseDescriptionKey = "websocket.ClientCloseDescription"; + } +} diff --git a/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs b/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs new file mode 100644 index 0000000000..f4887cc569 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.WebSockets +{ + // this class contains known header names + internal static class HttpKnownHeaderNames + { + public const string CacheControl = "Cache-Control"; + public const string Connection = "Connection"; + public const string Date = "Date"; + public const string KeepAlive = "Keep-Alive"; + public const string Pragma = "Pragma"; + public const string ProxyConnection = "Proxy-Connection"; + public const string Trailer = "Trailer"; + public const string TransferEncoding = "Transfer-Encoding"; + public const string Upgrade = "Upgrade"; + public const string Via = "Via"; + public const string Warning = "Warning"; + public const string ContentLength = "Content-Length"; + public const string ContentType = "Content-Type"; + public const string ContentDisposition = "Content-Disposition"; + public const string ContentEncoding = "Content-Encoding"; + public const string ContentLanguage = "Content-Language"; + public const string ContentLocation = "Content-Location"; + public const string ContentRange = "Content-Range"; + public const string Expires = "Expires"; + public const string LastModified = "Last-Modified"; + public const string Age = "Age"; + public const string Location = "Location"; + public const string ProxyAuthenticate = "Proxy-Authenticate"; + public const string RetryAfter = "Retry-After"; + public const string Server = "Server"; + public const string SetCookie = "Set-Cookie"; + public const string SetCookie2 = "Set-Cookie2"; + public const string Vary = "Vary"; + public const string WWWAuthenticate = "WWW-Authenticate"; + public const string Accept = "Accept"; + public const string AcceptCharset = "Accept-Charset"; + public const string AcceptEncoding = "Accept-Encoding"; + public const string AcceptLanguage = "Accept-Language"; + public const string Authorization = "Authorization"; + public const string Cookie = "Cookie"; + public const string Cookie2 = "Cookie2"; + public const string Expect = "Expect"; + public const string From = "From"; + public const string Host = "Host"; + public const string IfMatch = "If-Match"; + public const string IfModifiedSince = "If-Modified-Since"; + public const string IfNoneMatch = "If-None-Match"; + public const string IfRange = "If-Range"; + public const string IfUnmodifiedSince = "If-Unmodified-Since"; + public const string MaxForwards = "Max-Forwards"; + public const string ProxyAuthorization = "Proxy-Authorization"; + public const string Referer = "Referer"; + public const string Range = "Range"; + public const string UserAgent = "User-Agent"; + public const string ContentMD5 = "Content-MD5"; + public const string ETag = "ETag"; + public const string TE = "TE"; + public const string Allow = "Allow"; + public const string AcceptRanges = "Accept-Ranges"; + public const string P3P = "P3P"; + public const string XPoweredBy = "X-Powered-By"; + public const string XAspNetVersion = "X-AspNet-Version"; + public const string SecWebSocketKey = "Sec-WebSocket-Key"; + public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions"; + public const string SecWebSocketAccept = "Sec-WebSocket-Accept"; + public const string Origin = "Origin"; + public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol"; + public const string SecWebSocketVersion = "Sec-WebSocket-Version"; + } +} diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs new file mode 100644 index 0000000000..506c830ea2 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ +/* +namespace Microsoft.Net +{ + using Microsoft.AspNet.WebSockets; + using System; + using System.ComponentModel; + using System.Threading.Tasks; + + public sealed unsafe class HttpListenerContext { + private HttpListenerRequest m_Request; + + public Task AcceptWebSocketAsync(string subProtocol) + { + return this.AcceptWebSocketAsync(subProtocol, + WebSocketHelpers.DefaultReceiveBufferSize, + WebSocket.DefaultKeepAliveInterval); + } + + public Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval) + { + return this.AcceptWebSocketAsync(subProtocol, + WebSocketHelpers.DefaultReceiveBufferSize, + keepAliveInterval); + } + + public Task AcceptWebSocketAsync(string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval) + { + WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); + + ArraySegment internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + return this.AcceptWebSocketAsync(subProtocol, + receiveBufferSize, + keepAliveInterval, + internalBuffer); + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public Task AcceptWebSocketAsync(string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + { + return WebSocketHelpers.AcceptWebSocketAsync(this, + subProtocol, + receiveBufferSize, + keepAliveInterval, + internalBuffer); + } + } +} +*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs new file mode 100644 index 0000000000..d0c02c1842 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +/* +namespace Microsoft.Net +{ + using System; + using System.Collections; + using System.Collections.Specialized; + using System.IO; + using System.Runtime.InteropServices; + using System.Globalization; + using System.Text; + using System.Security.Principal; + using System.Security.Cryptography.X509Certificates; + using System.Net; + using Microsoft.AspNet.WebSockets; + + public sealed unsafe class HttpListenerRequest { + + public bool IsWebSocketRequest + { + get + { + if (!WebSocketProtocolComponent.IsSupported) + { + return false; + } + + bool foundConnectionUpgradeHeader = false; + if (string.IsNullOrEmpty(this.Headers[HttpKnownHeaderNames.Connection]) || string.IsNullOrEmpty(this.Headers[HttpKnownHeaderNames.Upgrade])) + { + return false; + } + + foreach (string connection in this.Headers.GetValues(HttpKnownHeaderNames.Connection)) + { + if (string.Compare(connection, HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) == 0) + { + foundConnectionUpgradeHeader = true; + break; + } + } + + if (!foundConnectionUpgradeHeader) + { + return false; + } + + foreach (string upgrade in this.Headers.GetValues(HttpKnownHeaderNames.Upgrade)) + { + if (string.Compare(upgrade, WebSocketHelpers.WebSocketUpgradeToken, StringComparison.OrdinalIgnoreCase) == 0) + { + return true; + } + } + + return false; + } + } + } +} +*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/SR.cs b/src/Microsoft.AspNet.WebSockets/Legacy/SR.cs new file mode 100644 index 0000000000..a8aeb2a30e --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/Legacy/SR.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// Information Contained Herein is Proprietary and Confidential. +// +//------------------------------------------------------------------------------ + +namespace System +{ + internal sealed class SR + { + internal const string net_servicePointAddressNotSupportedInHostMode = "net_servicePointAddressNotSupportedInHostMode"; + internal const string net_Websockets_AlreadyOneOutstandingOperation = "net_Websockets_AlreadyOneOutstandingOperation"; + internal const string net_Websockets_WebSocketBaseFaulted = "net_Websockets_WebSocketBaseFaulted"; + internal const string net_WebSockets_NativeSendResponseHeaders = "net_WebSockets_NativeSendResponseHeaders"; + internal const string net_WebSockets_Generic = "net_WebSockets_Generic"; + internal const string net_WebSockets_NotAWebSocket_Generic = "net_WebSockets_NotAWebSocket_Generic"; + internal const string net_WebSockets_UnsupportedWebSocketVersion_Generic = "net_WebSockets_UnsupportedWebSocketVersion_Generic"; + internal const string net_WebSockets_HeaderError_Generic = "net_WebSockets_HeaderError_Generic"; + internal const string net_WebSockets_UnsupportedProtocol_Generic = "net_WebSockets_UnsupportedProtocol_Generic"; + internal const string net_WebSockets_UnsupportedPlatform = "net_WebSockets_UnsupportedPlatform"; + internal const string net_WebSockets_AcceptNotAWebSocket = "net_WebSockets_AcceptNotAWebSocket"; + internal const string net_WebSockets_AcceptUnsupportedWebSocketVersion = "net_WebSockets_AcceptUnsupportedWebSocketVersion"; + internal const string net_WebSockets_AcceptHeaderNotFound = "net_WebSockets_AcceptHeaderNotFound"; + internal const string net_WebSockets_AcceptUnsupportedProtocol = "net_WebSockets_AcceptUnsupportedProtocol"; + internal const string net_WebSockets_ClientAcceptingNoProtocols = "net_WebSockets_ClientAcceptingNoProtocols"; + internal const string net_WebSockets_ClientSecWebSocketProtocolsBlank = "net_WebSockets_ClientSecWebSocketProtocolsBlank"; + internal const string net_WebSockets_ArgumentOutOfRange_TooSmall = "net_WebSockets_ArgumentOutOfRange_TooSmall"; + internal const string net_WebSockets_ArgumentOutOfRange_InternalBuffer = "net_WebSockets_ArgumentOutOfRange_InternalBuffer"; + internal const string net_WebSockets_ArgumentOutOfRange_TooBig = "net_WebSockets_ArgumentOutOfRange_TooBig"; + internal const string net_WebSockets_InvalidState_Generic = "net_WebSockets_InvalidState_Generic"; + internal const string net_WebSockets_InvalidState_ClosedOrAborted = "net_WebSockets_InvalidState_ClosedOrAborted"; + internal const string net_WebSockets_InvalidState = "net_WebSockets_InvalidState"; + internal const string net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync = "net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync"; + internal const string net_WebSockets_InvalidMessageType = "net_WebSockets_InvalidMessageType"; + internal const string net_WebSockets_InvalidBufferType = "net_WebSockets_InvalidBufferType"; + internal const string net_WebSockets_InvalidMessageType_Generic = "net_WebSockets_InvalidMessageType_Generic"; + internal const string net_WebSockets_Argument_InvalidMessageType = "net_WebSockets_Argument_InvalidMessageType"; + internal const string net_WebSockets_ConnectionClosedPrematurely_Generic = "net_WebSockets_ConnectionClosedPrematurely_Generic"; + internal const string net_WebSockets_InvalidCharInProtocolString = "net_WebSockets_InvalidCharInProtocolString"; + internal const string net_WebSockets_InvalidEmptySubProtocol = "net_WebSockets_InvalidEmptySubProtocol"; + internal const string net_WebSockets_ReasonNotNull = "net_WebSockets_ReasonNotNull"; + internal const string net_WebSockets_InvalidCloseStatusCode = "net_WebSockets_InvalidCloseStatusCode"; + internal const string net_WebSockets_InvalidCloseStatusDescription = "net_WebSockets_InvalidCloseStatusDescription"; + internal const string net_WebSockets_Scheme = "net_WebSockets_Scheme"; + internal const string net_WebSockets_AlreadyStarted = "net_WebSockets_AlreadyStarted"; + internal const string net_WebSockets_Connect101Expected = "net_WebSockets_Connect101Expected"; + internal const string net_WebSockets_InvalidResponseHeader = "net_WebSockets_InvalidResponseHeader"; + internal const string net_WebSockets_NotConnected = "net_WebSockets_NotConnected"; + internal const string net_WebSockets_InvalidRegistration = "net_WebSockets_InvalidRegistration"; + internal const string net_WebSockets_NoDuplicateProtocol = "net_WebSockets_NoDuplicateProtocol"; + + internal const string NotReadableStream = "NotReadableStream"; + internal const string NotWriteableStream = "NotWriteableStream"; + + public static string GetString(string name, params object[] args) + { + return name; + } + + public static string GetString(string name) + { + return name; + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs b/src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs new file mode 100644 index 0000000000..54abff91bd --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs @@ -0,0 +1,1262 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ +/* +namespace Microsoft.AspNet.WebSockets +{ + using Microsoft.Net; + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.IO; + using System.Runtime.InteropServices; + using System.Security; + using System.Threading; + using System.Threading.Tasks; + + internal class WebSocketHttpListenerDuplexStream : Stream, WebSocketBase.IWebSocketStream + { + private static readonly EventHandler s_OnReadCompleted = + new EventHandler(OnReadCompleted); + private static readonly EventHandler s_OnWriteCompleted = + new EventHandler(OnWriteCompleted); + private static readonly Func s_CanHandleException = new Func(CanHandleException); + private static readonly Action s_OnCancel = new Action(OnCancel); + // private readonly HttpRequestStream m_InputStream; + // private readonly HttpResponseStream m_OutputStream; + private HttpListenerContext m_Context; + private bool m_InOpaqueMode; + private WebSocketBase m_WebSocket; + private HttpListenerAsyncEventArgs m_WriteEventArgs; + private HttpListenerAsyncEventArgs m_ReadEventArgs; + private TaskCompletionSource m_WriteTaskCompletionSource; + private TaskCompletionSource m_ReadTaskCompletionSource; + private int m_CleanedUp; + +#if DEBUG + private class OutstandingOperations + { + internal int m_Reads; + internal int m_Writes; + } + + private readonly OutstandingOperations m_OutstandingOperations = new OutstandingOperations(); +#endif //DEBUG + + public WebSocketHttpListenerDuplexStream( + // HttpRequestStream inputStream, + // HttpResponseStream outputStream, + HttpListenerContext context) + { + Contract.Assert(inputStream != null, "'inputStream' MUST NOT be NULL."); + Contract.Assert(outputStream != null, "'outputStream' MUST NOT be NULL."); + Contract.Assert(context != null, "'context' MUST NOT be NULL."); + Contract.Assert(inputStream.CanRead, "'inputStream' MUST support read operations."); + Contract.Assert(outputStream.CanWrite, "'outputStream' MUST support write operations."); + + m_InputStream = inputStream; + m_OutputStream = outputStream; + m_Context = context; + + if (WebSocketBase.LoggingEnabled) + { + Logging.Associate(Logging.WebSockets, inputStream, this); + Logging.Associate(Logging.WebSockets, outputStream, this); + } + } + + public override bool CanRead + { + get + { + return m_InputStream.CanRead; + } + } + + public override bool CanSeek + { + get + { + return false; + } + } + + public override bool CanTimeout + { + get + { + return m_InputStream.CanTimeout && m_OutputStream.CanTimeout; + } + } + + public override bool CanWrite + { + get + { + return m_OutputStream.CanWrite; + } + } + + 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 int Read(byte[] buffer, int offset, int count) + { + return m_InputStream.Read(buffer, offset, count); + } + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + WebSocketHelpers.ValidateBuffer(buffer, offset, count); + + return ReadAsyncCore(buffer, offset, count, cancellationToken); + } + + private async Task ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, this, Methods.ReadAsyncCore, + WebSocketHelpers.GetTraceMsgForParameters(offset, count, cancellationToken)); + } + + CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration(); + + int bytesRead = 0; + try + { + if (cancellationToken.CanBeCanceled) + { + cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); + } + + if (!m_InOpaqueMode) + { + bytesRead = await m_InputStream.ReadAsync(buffer, offset, count, cancellationToken).SuppressContextFlow(); + } + else + { +#if DEBUG + // When using fast path only one outstanding read is permitted. By switching into opaque mode + // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) + // caller takes responsibility for enforcing this constraint. + Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Reads) == 1, + "Only one outstanding read allowed at any given time."); +#endif + m_ReadTaskCompletionSource = new TaskCompletionSource(); + m_ReadEventArgs.SetBuffer(buffer, offset, count); + if (!ReadAsyncFast(m_ReadEventArgs)) + { + if (m_ReadEventArgs.Exception != null) + { + throw m_ReadEventArgs.Exception; + } + + bytesRead = m_ReadEventArgs.BytesTransferred; + } + else + { + bytesRead = await m_ReadTaskCompletionSource.Task.SuppressContextFlow(); + } + } + } + catch (Exception error) + { + if (s_CanHandleException(error)) + { + cancellationToken.ThrowIfCancellationRequested(); + } + + throw; + } + finally + { + cancellationTokenRegistration.Dispose(); + + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.ReadAsyncCore, bytesRead); + } + } + + return bytesRead; + } + + // return value indicates sync vs async completion + // false: sync completion + // true: async completion + private unsafe bool ReadAsyncFast(HttpListenerAsyncEventArgs eventArgs) + { + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, this, Methods.ReadAsyncFast, string.Empty); + } + + eventArgs.StartOperationCommon(this); + eventArgs.StartOperationReceive(); + + uint statusCode = 0; + bool completedAsynchronously = false; + try + { + Contract.Assert(eventArgs.Buffer != null, "'BufferList' is not supported for read operations."); + if (eventArgs.Count == 0 || m_InputStream.Closed) + { + eventArgs.FinishOperationSuccess(0, true); + return false; + } + + uint dataRead = 0; + int offset = eventArgs.Offset; + int remainingCount = eventArgs.Count; + + if (m_InputStream.BufferedDataChunksAvailable) + { + dataRead = m_InputStream.GetChunks(eventArgs.Buffer, eventArgs.Offset, eventArgs.Count); + if (m_InputStream.BufferedDataChunksAvailable && dataRead == eventArgs.Count) + { + eventArgs.FinishOperationSuccess(eventArgs.Count, true); + return false; + } + } + + Contract.Assert(!m_InputStream.BufferedDataChunksAvailable, "'m_InputStream.BufferedDataChunksAvailable' MUST BE 'FALSE' at this point."); + Contract.Assert(dataRead <= eventArgs.Count, "'dataRead' MUST NOT be bigger than 'eventArgs.Count'."); + + if (dataRead != 0) + { + offset += (int)dataRead; + remainingCount -= (int)dataRead; + //the http.sys team recommends that we limit the size to 128kb + if (remainingCount > HttpRequestStream.MaxReadSize) + { + remainingCount = HttpRequestStream.MaxReadSize; + } + + eventArgs.SetBuffer(eventArgs.Buffer, offset, remainingCount); + } + else if (remainingCount > HttpRequestStream.MaxReadSize) + { + remainingCount = HttpRequestStream.MaxReadSize; + eventArgs.SetBuffer(eventArgs.Buffer, offset, remainingCount); + } + + // m_InputStream.InternalHttpContext.EnsureBoundHandle(); + uint flags = 0; + uint bytesReturned = 0; + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody2( + m_InputStream.InternalHttpContext.RequestQueueHandle, + m_InputStream.InternalHttpContext.RequestId, + flags, + (byte*)m_WebSocket.InternalBuffer.ToIntPtr(eventArgs.Offset), + (uint)eventArgs.Count, + out bytesReturned, + eventArgs.NativeOverlapped); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING && + statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + throw new HttpListenerException((int)statusCode); + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + HttpListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously. No IO completion port callback is used because + // it was disabled in SwitchToOpaqueMode() + eventArgs.FinishOperationSuccess((int)bytesReturned, true); + completedAsynchronously = false; + } + else + { + completedAsynchronously = true; + } + } + catch (Exception e) + { + m_ReadEventArgs.FinishOperationFailure(e, true); + m_OutputStream.SetClosedFlag(); + m_OutputStream.InternalHttpContext.Abort(); + + throw; + } + finally + { + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.ReadAsyncFast, completedAsynchronously); + } + } + + return completedAsynchronously; + } + + public override int ReadByte() + { + return m_InputStream.ReadByte(); + } + + public bool SupportsMultipleWrite + { + get + { + return true; + } + } + + public override IAsyncResult BeginRead(byte[] buffer, + int offset, + int count, + AsyncCallback callback, + object state) + { + return m_InputStream.BeginRead(buffer, offset, count, callback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + return m_InputStream.EndRead(asyncResult); + } + + public Task MultipleWriteAsync(IList> sendBuffers, CancellationToken cancellationToken) + { + Contract.Assert(m_InOpaqueMode, "The stream MUST be in opaque mode at this point."); + Contract.Assert(sendBuffers != null, "'sendBuffers' MUST NOT be NULL."); + Contract.Assert(sendBuffers.Count == 1 || sendBuffers.Count == 2, + "'sendBuffers.Count' MUST be either '1' or '2'."); + + if (sendBuffers.Count == 1) + { + ArraySegment buffer = sendBuffers[0]; + return WriteAsync(buffer.Array, buffer.Offset, buffer.Count, cancellationToken); + } + + return MultipleWriteAsyncCore(sendBuffers, cancellationToken); + } + + private async Task MultipleWriteAsyncCore(IList> sendBuffers, CancellationToken cancellationToken) + { + Contract.Assert(sendBuffers != null, "'sendBuffers' MUST NOT be NULL."); + Contract.Assert(sendBuffers.Count == 2, "'sendBuffers.Count' MUST be '2' at this point."); + + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, this, Methods.MultipleWriteAsyncCore, string.Empty); + } + + CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration(); + + try + { + if (cancellationToken.CanBeCanceled) + { + cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); + } +#if DEBUG + // When using fast path only one outstanding read is permitted. By switching into opaque mode + // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) + // caller takes responsibility for enforcing this constraint. + Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Writes) == 1, + "Only one outstanding write allowed at any given time."); +#endif + m_WriteTaskCompletionSource = new TaskCompletionSource(); + m_WriteEventArgs.SetBuffer(null, 0, 0); + m_WriteEventArgs.BufferList = sendBuffers; + if (WriteAsyncFast(m_WriteEventArgs)) + { + await m_WriteTaskCompletionSource.Task.SuppressContextFlow(); + } + } + catch (Exception error) + { + if (s_CanHandleException(error)) + { + cancellationToken.ThrowIfCancellationRequested(); + } + + throw; + } + finally + { + cancellationTokenRegistration.Dispose(); + + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.MultipleWriteAsyncCore, string.Empty); + } + } + } + + public override void Write(byte[] buffer, int offset, int count) + { + m_OutputStream.Write(buffer, offset, count); + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + WebSocketHelpers.ValidateBuffer(buffer, offset, count); + + return WriteAsyncCore(buffer, offset, count, cancellationToken); + } + + private async Task WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, this, Methods.WriteAsyncCore, + WebSocketHelpers.GetTraceMsgForParameters(offset, count, cancellationToken)); + } + + CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration(); + + try + { + if (cancellationToken.CanBeCanceled) + { + cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); + } + + if (!m_InOpaqueMode) + { + await m_OutputStream.WriteAsync(buffer, offset, count, cancellationToken).SuppressContextFlow(); + } + else + { +#if DEBUG + // When using fast path only one outstanding read is permitted. By switching into opaque mode + // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) + // caller takes responsibility for enforcing this constraint. + Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Writes) == 1, + "Only one outstanding write allowed at any given time."); +#endif + m_WriteTaskCompletionSource = new TaskCompletionSource(); + m_WriteEventArgs.BufferList = null; + m_WriteEventArgs.SetBuffer(buffer, offset, count); + if (WriteAsyncFast(m_WriteEventArgs)) + { + await m_WriteTaskCompletionSource.Task.SuppressContextFlow(); + } + } + } + catch (Exception error) + { + if (s_CanHandleException(error)) + { + cancellationToken.ThrowIfCancellationRequested(); + } + + throw; + } + finally + { + cancellationTokenRegistration.Dispose(); + + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.WriteAsyncCore, string.Empty); + } + } + } + + // return value indicates sync vs async completion + // false: sync completion + // true: async completion + private bool WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs) + { + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, this, Methods.WriteAsyncFast, string.Empty); + } + + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + + eventArgs.StartOperationCommon(this); + eventArgs.StartOperationSend(); + + uint statusCode; + bool completedAsynchronously = false; + try + { + if (m_OutputStream.Closed || + (eventArgs.Buffer != null && eventArgs.Count == 0)) + { + eventArgs.FinishOperationSuccess(eventArgs.Count, true); + return false; + } + + if (eventArgs.ShouldCloseOutput) + { + flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; + } + else + { + flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + // When using HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA HTTP.SYS will copy the payload to + // kernel memory (Non-Paged Pool). Http.Sys will buffer up to + // Math.Min(16 MB, current TCP window size) + flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA; + } + + m_OutputStream.InternalHttpContext.EnsureBoundHandle(); + uint bytesSent; + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody2( + m_OutputStream.InternalHttpContext.RequestQueueHandle, + m_OutputStream.InternalHttpContext.RequestId, + (uint)flags, + eventArgs.EntityChunkCount, + eventArgs.EntityChunks, + out bytesSent, + SafeLocalFree.Zero, + 0, + eventArgs.NativeOverlapped, + IntPtr.Zero); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + throw new HttpListenerException((int)statusCode); + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + HttpListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + eventArgs.FinishOperationSuccess((int)bytesSent, true); + completedAsynchronously = false; + } + else + { + completedAsynchronously = true; + } + } + catch (Exception e) + { + m_WriteEventArgs.FinishOperationFailure(e, true); + m_OutputStream.SetClosedFlag(); + m_OutputStream.InternalHttpContext.Abort(); + + throw; + } + finally + { + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.WriteAsyncFast, completedAsynchronously); + } + } + + return completedAsynchronously; + } + + public override void WriteByte(byte value) + { + m_OutputStream.WriteByte(value); + } + + public override IAsyncResult BeginWrite(byte[] buffer, + int offset, + int count, + AsyncCallback callback, + object state) + { + return m_OutputStream.BeginWrite(buffer, offset, count, callback, state); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + m_OutputStream.EndWrite(asyncResult); + } + + public override void Flush() + { + m_OutputStream.Flush(); + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + return m_OutputStream.FlushAsync(cancellationToken); + } + + 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 async Task CloseNetworkConnectionAsync(CancellationToken cancellationToken) + { + // need to yield here to make sure that we don't get any exception synchronously + await Task.Yield(); + + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, this, Methods.CloseNetworkConnectionAsync, string.Empty); + } + + CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration(); + + try + { + if (cancellationToken.CanBeCanceled) + { + cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); + } +#if DEBUG + // When using fast path only one outstanding read is permitted. By switching into opaque mode + // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) + // caller takes responsibility for enforcing this constraint. + Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Writes) == 1, + "Only one outstanding write allowed at any given time."); +#endif + m_WriteTaskCompletionSource = new TaskCompletionSource(); + m_WriteEventArgs.SetShouldCloseOutput(); + if (WriteAsyncFast(m_WriteEventArgs)) + { + await m_WriteTaskCompletionSource.Task.SuppressContextFlow(); + } + } + catch (Exception error) + { + if (!s_CanHandleException(error)) + { + throw; + } + + // throw OperationCancelledException when canceled by the caller + // otherwise swallow the exception + cancellationToken.ThrowIfCancellationRequested(); + } + finally + { + cancellationTokenRegistration.Dispose(); + + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.CloseNetworkConnectionAsync, string.Empty); + } + } + } + + protected override void Dispose(bool disposing) + { + if (disposing && Interlocked.Exchange(ref m_CleanedUp, 1) == 0) + { + if (m_ReadTaskCompletionSource != null) + { + m_ReadTaskCompletionSource.TrySetCanceled(); + } + + if (m_WriteTaskCompletionSource != null) + { + m_WriteTaskCompletionSource.TrySetCanceled(); + } + + if (m_ReadEventArgs != null) + { + m_ReadEventArgs.Dispose(); + } + + if (m_WriteEventArgs != null) + { + m_WriteEventArgs.Dispose(); + } + + try + { + m_InputStream.Close(); + } + finally + { + m_OutputStream.Close(); + } + } + } + + public void Abort() + { + OnCancel(this); + } + + private static bool CanHandleException(Exception error) + { + return error is HttpListenerException || + error is ObjectDisposedException || + error is IOException; + } + + private static void OnCancel(object state) + { + Contract.Assert(state != null, "'state' MUST NOT be NULL."); + WebSocketHttpListenerDuplexStream thisPtr = state as WebSocketHttpListenerDuplexStream; + Contract.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL."); + + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, state, Methods.OnCancel, string.Empty); + } + + try + { + thisPtr.m_OutputStream.SetClosedFlag(); + // thisPtr.m_Context.Abort(); + } + catch { } + + TaskCompletionSource readTaskCompletionSourceSnapshot = thisPtr.m_ReadTaskCompletionSource; + + if (readTaskCompletionSourceSnapshot != null) + { + readTaskCompletionSourceSnapshot.TrySetCanceled(); + } + + TaskCompletionSource writeTaskCompletionSourceSnapshot = thisPtr.m_WriteTaskCompletionSource; + + if (writeTaskCompletionSourceSnapshot != null) + { + writeTaskCompletionSourceSnapshot.TrySetCanceled(); + } + + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, state, Methods.OnCancel, string.Empty); + } + } + + public void SwitchToOpaqueMode(WebSocketBase webSocket) + { + Contract.Assert(webSocket != null, "'webSocket' MUST NOT be NULL."); + Contract.Assert(m_OutputStream != null, "'m_OutputStream' MUST NOT be NULL."); + Contract.Assert(m_OutputStream.InternalHttpContext != null, + "'m_OutputStream.InternalHttpContext' MUST NOT be NULL."); + Contract.Assert(m_OutputStream.InternalHttpContext.Response != null, + "'m_OutputStream.InternalHttpContext.Response' MUST NOT be NULL."); + Contract.Assert(m_OutputStream.InternalHttpContext.Response.SentHeaders, + "Headers MUST have been sent at this point."); + Contract.Assert(!m_InOpaqueMode, "SwitchToOpaqueMode MUST NOT be called multiple times."); + + if (m_InOpaqueMode) + { + throw new InvalidOperationException(); + } + + m_WebSocket = webSocket; + m_InOpaqueMode = true; + m_ReadEventArgs = new HttpListenerAsyncEventArgs(webSocket, this); + m_ReadEventArgs.Completed += s_OnReadCompleted; + m_WriteEventArgs = new HttpListenerAsyncEventArgs(webSocket, this); + m_WriteEventArgs.Completed += s_OnWriteCompleted; + + if (WebSocketBase.LoggingEnabled) + { + Logging.Associate(Logging.WebSockets, this, webSocket); + } + } + + private static void OnWriteCompleted(object sender, HttpListenerAsyncEventArgs eventArgs) + { + Contract.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL."); + WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream; + Contract.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL."); +#if DEBUG + Contract.Assert(Interlocked.Decrement(ref thisPtr.m_OutstandingOperations.m_Writes) >= 0, + "'thisPtr.m_OutstandingOperations.m_Writes' MUST NOT be negative."); +#endif + + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, thisPtr, Methods.OnWriteCompleted, string.Empty); + } + + if (eventArgs.Exception != null) + { + thisPtr.m_WriteTaskCompletionSource.TrySetException(eventArgs.Exception); + } + else + { + thisPtr.m_WriteTaskCompletionSource.TrySetResult(null); + } + + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, thisPtr, Methods.OnWriteCompleted, string.Empty); + } + } + + private static void OnReadCompleted(object sender, HttpListenerAsyncEventArgs eventArgs) + { + Contract.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL."); + WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream; + Contract.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL."); +#if DEBUG + Contract.Assert(Interlocked.Decrement(ref thisPtr.m_OutstandingOperations.m_Reads) >= 0, + "'thisPtr.m_OutstandingOperations.m_Reads' MUST NOT be negative."); +#endif + + if (WebSocketBase.LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, thisPtr, Methods.OnReadCompleted, string.Empty); + } + + if (eventArgs.Exception != null) + { + thisPtr.m_ReadTaskCompletionSource.TrySetException(eventArgs.Exception); + } + else + { + thisPtr.m_ReadTaskCompletionSource.TrySetResult(eventArgs.BytesTransferred); + } + + if (WebSocketBase.LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, thisPtr, Methods.OnReadCompleted, string.Empty); + } + } + + internal class HttpListenerAsyncEventArgs : EventArgs, IDisposable + { + private const int Free = 0; + private const int InProgress = 1; + private const int Disposed = 2; + private int m_Operating; + + private bool m_DisposeCalled; + private SafeNativeOverlapped m_PtrNativeOverlapped; + private Overlapped m_Overlapped; + private event EventHandler m_Completed; + private byte[] m_Buffer; + private IList> m_BufferList; + private int m_Count; + private int m_Offset; + private int m_BytesTransferred; + private HttpListenerAsyncOperation m_CompletedOperation; + private UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[] m_DataChunks; + private GCHandle m_DataChunksGCHandle; + private ushort m_DataChunkCount; + private Exception m_Exception; + private bool m_ShouldCloseOutput; + private readonly WebSocketBase m_WebSocket; + private readonly WebSocketHttpListenerDuplexStream m_CurrentStream; + + public HttpListenerAsyncEventArgs(WebSocketBase webSocket, WebSocketHttpListenerDuplexStream stream) + : base() + { + m_WebSocket = webSocket; + m_CurrentStream = stream; + InitializeOverlapped(); + } + + public int BytesTransferred + { + get { return m_BytesTransferred; } + } + + public byte[] Buffer + { + get { return m_Buffer; } + } + + // BufferList property. + // Mutually exclusive with Buffer. + // Setting this property with an existing non-null Buffer will cause an assert. + public IList> BufferList + { + get { return m_BufferList; } + set + { + Contract.Assert(!m_ShouldCloseOutput, "'m_ShouldCloseOutput' MUST be 'false' at this point."); + Contract.Assert(value == null || m_Buffer == null, + "Either 'm_Buffer' or 'm_BufferList' MUST be NULL."); + Contract.Assert(m_Operating == Free, + "This property can only be modified if no IO operation is outstanding."); + Contract.Assert(value == null || value.Count == 2, + "This list can only be 'NULL' or MUST have exactly '2' items."); + m_BufferList = value; + } + } + + public bool ShouldCloseOutput + { + get { return m_ShouldCloseOutput; } + } + + public int Offset + { + get { return m_Offset; } + } + + public int Count + { + get { return m_Count; } + } + + public Exception Exception + { + get { return m_Exception; } + } + + public ushort EntityChunkCount + { + get + { + if (m_DataChunks == null) + { + return 0; + } + + return m_DataChunkCount; + } + } + + public SafeNativeOverlapped NativeOverlapped + { + get { return m_PtrNativeOverlapped; } + } + + public IntPtr EntityChunks + { + get + { + if (m_DataChunks == null) + { + return IntPtr.Zero; + } + + return Marshal.UnsafeAddrOfPinnedArrayElement(m_DataChunks, 0); + } + } + + public WebSocketHttpListenerDuplexStream CurrentStream + { + get { return m_CurrentStream; } + } + + public event EventHandler Completed + { + add + { + m_Completed += value; + } + remove + { + m_Completed -= value; + } + } + + protected virtual void OnCompleted(HttpListenerAsyncEventArgs e) + { + EventHandler handler = m_Completed; + if (handler != null) + { + handler(e.m_CurrentStream, e); + } + } + + public void SetShouldCloseOutput() + { + m_BufferList = null; + m_Buffer = null; + m_ShouldCloseOutput = true; + } + + public void Dispose() + { + // Remember that Dispose was called. + m_DisposeCalled = true; + + // Check if this object is in-use for an async socket operation. + if (Interlocked.CompareExchange(ref m_Operating, Disposed, Free) != Free) + { + // Either already disposed or will be disposed when current operation completes. + return; + } + + // OK to dispose now. + // Free native overlapped data. + FreeOverlapped(false); + + // Don't bother finalizing later. + GC.SuppressFinalize(this); + } + + // Finalizer + ~HttpListenerAsyncEventArgs() + { + FreeOverlapped(true); + } + + private unsafe void InitializeOverlapped() + { + m_Overlapped = new Overlapped(); + m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, null)); + } + + // Method to clean up any existing Overlapped object and related state variables. + private void FreeOverlapped(bool checkForShutdown) + { + if (!checkForShutdown || !NclUtilities.HasShutdownStarted) + { + // Free the overlapped object + if (m_PtrNativeOverlapped != null && !m_PtrNativeOverlapped.IsInvalid) + { + m_PtrNativeOverlapped.Dispose(); + } + + if (m_DataChunksGCHandle.IsAllocated) + { + m_DataChunksGCHandle.Free(); + } + } + } + + // Method called to prepare for a native async http.sys call. + // This method performs the tasks common to all http.sys operations. + internal void StartOperationCommon(WebSocketHttpListenerDuplexStream currentStream) + { + // Change status to "in-use". + if(Interlocked.CompareExchange(ref m_Operating, InProgress, Free) != Free) + { + // If it was already "in-use" check if Dispose was called. + if (m_DisposeCalled) + { + // Dispose was called - throw ObjectDisposed. + throw new ObjectDisposedException(GetType().FullName); + } + + Contract.Assert(false, "Only one outstanding async operation is allowed per HttpListenerAsyncEventArgs instance."); + // Only one at a time. + throw new InvalidOperationException(); + } + + // HttpSendResponseEntityBody can return ERROR_INVALID_PARAMETER if the InternalHigh field of the overlapped + // is not IntPtr.Zero, so we have to reset this field because we are reusing the Overlapped. + // When using the IAsyncResult based approach of HttpListenerResponseStream the Overlapped is reinitialized + // for each operation by the CLR when returned from the OverlappedDataCache. + NativeOverlapped.ReinitializeNativeOverlapped(); + m_Exception = null; + m_BytesTransferred = 0; + } + + internal void StartOperationReceive() + { + // Remember the operation type. + m_CompletedOperation = HttpListenerAsyncOperation.Receive; + } + + internal void StartOperationSend() + { + UpdateDataChunk(); + + // Remember the operation type. + m_CompletedOperation = HttpListenerAsyncOperation.Send; + } + + public void SetBuffer(byte[] buffer, int offset, int count) + { + Contract.Assert(!m_ShouldCloseOutput, "'m_ShouldCloseOutput' MUST be 'false' at this point."); + Contract.Assert(buffer == null || m_BufferList == null, "Either 'm_Buffer' or 'm_BufferList' MUST be NULL."); + m_Buffer = buffer; + m_Offset = offset; + m_Count = count; + } + + private unsafe void UpdateDataChunk() + { + if (m_DataChunks == null) + { + m_DataChunks = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[2]; + m_DataChunksGCHandle = GCHandle.Alloc(m_DataChunks); + m_DataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + m_DataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + m_DataChunks[1] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); + m_DataChunks[1].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + } + + Contract.Assert(m_Buffer == null || m_BufferList == null, "Either 'm_Buffer' or 'm_BufferList' MUST be NULL."); + Contract.Assert(m_ShouldCloseOutput || m_Buffer != null || m_BufferList != null, "Either 'm_Buffer' or 'm_BufferList' MUST NOT be NULL."); + + // The underlying byte[] m_Buffer or each m_BufferList[].Array are pinned already + if (m_Buffer != null) + { + UpdateDataChunk(0, m_Buffer, m_Offset, m_Count); + UpdateDataChunk(1, null, 0, 0); + m_DataChunkCount = 1; + } + else if (m_BufferList != null) + { + Contract.Assert(m_BufferList != null && m_BufferList.Count == 2, + "'m_BufferList' MUST NOT be NULL and have exactly '2' items at this point."); + UpdateDataChunk(0, m_BufferList[0].Array, m_BufferList[0].Offset, m_BufferList[0].Count); + UpdateDataChunk(1, m_BufferList[1].Array, m_BufferList[1].Offset, m_BufferList[1].Count); + m_DataChunkCount = 2; + } + else + { + Contract.Assert(m_ShouldCloseOutput, "'m_ShouldCloseOutput' MUST be 'true' at this point."); + m_DataChunks = null; + } + } + + private unsafe void UpdateDataChunk(int index, byte[] buffer, int offset, int count) + { + if (buffer == null) + { + m_DataChunks[index].pBuffer = null; + m_DataChunks[index].BufferLength = 0; + return; + } + + if (m_WebSocket.InternalBuffer.IsInternalBuffer(buffer, offset, count)) + { + m_DataChunks[index].pBuffer = (byte*)(m_WebSocket.InternalBuffer.ToIntPtr(offset)); + } + else + { + m_DataChunks[index].pBuffer = + (byte*)m_WebSocket.InternalBuffer.ConvertPinnedSendPayloadToNative(buffer, offset, count); + } + + m_DataChunks[index].BufferLength = (uint)count; + } + + // Method to mark this object as no longer "in-use". + // Will also execute a Dispose deferred because I/O was in progress. + internal void Complete() + { + // Mark as not in-use + m_Operating = Free; + + // Check for deferred Dispose(). + // The deferred Dispose is not guaranteed if Dispose is called while an operation is in progress. + // The m_DisposeCalled variable is not managed in a thread-safe manner on purpose for performance. + if (m_DisposeCalled) + { + Dispose(); + } + } + + // Method to update internal state after sync or async completion. + private void SetResults(Exception exception, int bytesTransferred) + { + m_Exception = exception; + m_BytesTransferred = bytesTransferred; + } + + internal void FinishOperationFailure(Exception exception, bool syncCompletion) + { + SetResults(exception, 0); + + if (WebSocketBase.LoggingEnabled) + { + Logging.PrintError(Logging.WebSockets, m_CurrentStream, + m_CompletedOperation == HttpListenerAsyncOperation.Receive ? Methods.ReadAsyncFast : Methods.WriteAsyncFast, + exception.ToString()); + } + + Complete(); + OnCompleted(this); + } + + internal void FinishOperationSuccess(int bytesTransferred, bool syncCompletion) + { + SetResults(null, bytesTransferred); + + if (WebSocketBase.LoggingEnabled) + { + if (m_Buffer != null) + { + Logging.Dump(Logging.WebSockets, m_CurrentStream, + m_CompletedOperation == HttpListenerAsyncOperation.Receive ? Methods.ReadAsyncFast : Methods.WriteAsyncFast, + m_Buffer, m_Offset, bytesTransferred); + } + else if (m_BufferList != null) + { + Contract.Assert(m_CompletedOperation == HttpListenerAsyncOperation.Send, + "'BufferList' is only supported for send operations."); + + foreach (ArraySegment buffer in BufferList) + { + Logging.Dump(Logging.WebSockets, this, Methods.WriteAsyncFast, buffer.Array, buffer.Offset, buffer.Count); + } + } + else + { + Logging.PrintLine(Logging.WebSockets, TraceEventType.Verbose, 0, + string.Format(CultureInfo.InvariantCulture, "Output channel closed for {0}#{1}", + m_CurrentStream.GetType().Name, ValidationHelper.HashString(m_CurrentStream))); + } + } + + if (m_ShouldCloseOutput) + { + m_CurrentStream.m_OutputStream.SetClosedFlag(); + } + + // Complete the operation and raise completion event. + Complete(); + OnCompleted(this); + } + + private unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) + { + if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS || + errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + FinishOperationSuccess((int)numBytes, false); + } + else + { + FinishOperationFailure(new HttpListenerException((int)errorCode), false); + } + } + + public enum HttpListenerAsyncOperation + { + None, + Receive, + Send + } + } + + private static class Methods + { + public const string CloseNetworkConnectionAsync = "CloseNetworkConnectionAsync"; + public const string OnCancel = "OnCancel"; + public const string OnReadCompleted = "OnReadCompleted"; + public const string OnWriteCompleted = "OnWriteCompleted"; + public const string ReadAsyncFast = "ReadAsyncFast"; + public const string ReadAsyncCore = "ReadAsyncCore"; + public const string WriteAsyncFast = "WriteAsyncFast"; + public const string WriteAsyncCore = "WriteAsyncCore"; + public const string MultipleWriteAsyncCore = "MultipleWriteAsyncCore"; + } + } +} +*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs new file mode 100644 index 0000000000..43276eefe5 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.WebSockets +{ + internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid + { + private const string KERNEL32 = "kernel32.dll"; + + public static readonly SafeLoadLibrary Zero = new SafeLoadLibrary(false); + + private SafeLoadLibrary() : base(true) + { + } + + private SafeLoadLibrary(bool ownsHandle) : base(ownsHandle) + { + } + + public static unsafe SafeLoadLibrary LoadLibraryEx(string library) + { + SafeLoadLibrary result = UnsafeNativeMethods.SafeNetHandles.LoadLibraryExW(library, null, 0); + if (result.IsInvalid) + { + result.SetHandleAsInvalid(); + } + return result; + } + + protected override bool ReleaseHandle() + { + return UnsafeNativeMethods.SafeNetHandles.FreeLibrary(handle); + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs new file mode 100644 index 0000000000..8682c89918 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Microsoft.AspNet.WebSockets +{ + internal class SafeNativeOverlapped : SafeHandle + { + internal static readonly SafeNativeOverlapped Zero = new SafeNativeOverlapped(); + + internal SafeNativeOverlapped() + : this(IntPtr.Zero) + { + } + + internal unsafe SafeNativeOverlapped(NativeOverlapped* handle) + : this((IntPtr)handle) + { + } + + internal SafeNativeOverlapped(IntPtr handle) + : base(IntPtr.Zero, true) + { + SetHandle(handle); + } + + public override bool IsInvalid + { + get { return handle == IntPtr.Zero; } + } + + public void ReinitializeNativeOverlapped() + { + IntPtr handleSnapshot = handle; + + if (handleSnapshot != IntPtr.Zero) + { + unsafe + { + ((NativeOverlapped*)handleSnapshot)->InternalHigh = IntPtr.Zero; + ((NativeOverlapped*)handleSnapshot)->InternalLow = IntPtr.Zero; + ((NativeOverlapped*)handleSnapshot)->EventHandle = IntPtr.Zero; + } + } + } + + protected override bool ReleaseHandle() + { + IntPtr oldHandle = Interlocked.Exchange(ref handle, IntPtr.Zero); + // Do not call free durring AppDomain shutdown, there may be an outstanding operation. + // Overlapped will take care calling free when the native callback completes. + if (oldHandle != IntPtr.Zero && !HasShutdownStarted) + { + unsafe + { + Overlapped.Free((NativeOverlapped*)oldHandle); + } + } + return true; + } + + internal static bool HasShutdownStarted + { + get + { + return Environment.HasShutdownStarted +#if NET45 + || AppDomain.CurrentDomain.IsFinalizingForUnload() +#endif + ; + } + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs new file mode 100644 index 0000000000..60c8341561 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using Microsoft.AspNet.WebSockets; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.AspNet.WebSockets +{ + // This class is a wrapper for a WSPC (WebSocket protocol component) session. WebSocketCreateClientHandle and WebSocketCreateServerHandle return a PVOID and not a real handle + // but we use a SafeHandle because it provides us the guarantee that WebSocketDeleteHandle will always get called. + internal sealed class SafeWebSocketHandle : SafeHandleZeroOrMinusOneIsInvalid + { + internal SafeWebSocketHandle() + : base(true) + { + } + + protected override bool ReleaseHandle() + { + if (this.IsInvalid) + { + return true; + } + + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketDeleteHandle(this.handle); + return true; + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs new file mode 100644 index 0000000000..86355cdee4 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -0,0 +1,842 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.Contracts; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Microsoft.AspNet.WebSockets +{ + internal static class UnsafeNativeMethods + { + private const string KERNEL32 = "kernel32.dll"; + private const string WEBSOCKET = "websocket.dll"; + + internal static class SafeNetHandles + { + [DllImport(KERNEL32, ExactSpelling = true, CharSet=CharSet.Unicode, SetLastError = true)] + internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); + + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] + internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); + } + + internal static class WebSocketProtocolComponent + { + private static readonly string DllFileName; + private static readonly string DummyWebsocketKeyBase64 = Convert.ToBase64String(new byte[16]); + private static readonly SafeLoadLibrary WebSocketDllHandle; + private static readonly string PrivateSupportedVersion; + + private static readonly HttpHeader[] InitialClientRequestHeaders = new HttpHeader[] + { + new HttpHeader() + { + Name = HttpKnownHeaderNames.Connection, + NameLength = (uint)HttpKnownHeaderNames.Connection.Length, + Value = HttpKnownHeaderNames.Upgrade, + ValueLength = (uint)HttpKnownHeaderNames.Upgrade.Length + }, + new HttpHeader() + { + Name = HttpKnownHeaderNames.Upgrade, + NameLength = (uint)HttpKnownHeaderNames.Upgrade.Length, + Value = WebSocketHelpers.WebSocketUpgradeToken, + ValueLength = (uint)WebSocketHelpers.WebSocketUpgradeToken.Length + } + }; + + private static readonly HttpHeader[] ServerFakeRequestHeaders; + + internal static class Errors + { + internal const int E_INVALID_OPERATION = unchecked((int)0x80000050); + internal const int E_INVALID_PROTOCOL_OPERATION = unchecked((int)0x80000051); + internal const int E_INVALID_PROTOCOL_FORMAT = unchecked((int)0x80000052); + internal const int E_NUMERIC_OVERFLOW = unchecked((int)0x80000053); + internal const int E_FAIL = unchecked((int)0x80004005); + } + + internal enum Action + { + NoAction = 0, + SendToNetwork = 1, + IndicateSendComplete = 2, + ReceiveFromNetwork = 3, + IndicateReceiveComplete = 4, + } + + internal enum BufferType : uint + { + None = 0x00000000, + UTF8Message = 0x80000000, + UTF8Fragment = 0x80000001, + BinaryMessage = 0x80000002, + BinaryFragment = 0x80000003, + Close = 0x80000004, + PingPong = 0x80000005, + UnsolicitedPong = 0x80000006 + } + + internal enum PropertyType + { + ReceiveBufferSize = 0, + SendBufferSize = 1, + DisableMasking = 2, + AllocatedBuffer = 3, + DisableUtf8Verification = 4, + KeepAliveInterval = 5, + } + + internal enum ActionQueue + { + Send = 1, + Receive = 2, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct Property + { + internal PropertyType Type; + internal IntPtr PropertyData; + internal uint PropertySize; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct Buffer + { + [FieldOffset(0)] + internal DataBuffer Data; + [FieldOffset(0)] + internal CloseBuffer CloseStatus; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct DataBuffer + { + internal IntPtr BufferData; + internal uint BufferLength; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct CloseBuffer + { + internal IntPtr ReasonData; + internal uint ReasonLength; + internal ushort CloseStatus; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HttpHeader + { + [MarshalAs(UnmanagedType.LPStr)] + internal string Name; + internal uint NameLength; + [MarshalAs(UnmanagedType.LPStr)] + internal string Value; + internal uint ValueLength; + } + + static WebSocketProtocolComponent() + { + DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); + WebSocketDllHandle = SafeLoadLibrary.LoadLibraryEx(DllFileName); + + if (!WebSocketDllHandle.IsInvalid) + { + PrivateSupportedVersion = GetSupportedVersion(); + + ServerFakeRequestHeaders = new HttpHeader[] + { + new HttpHeader() + { + Name = HttpKnownHeaderNames.Connection, + NameLength = (uint)HttpKnownHeaderNames.Connection.Length, + Value = HttpKnownHeaderNames.Upgrade, + ValueLength = (uint)HttpKnownHeaderNames.Upgrade.Length + }, + new HttpHeader() + { + Name = HttpKnownHeaderNames.Upgrade, + NameLength = (uint)HttpKnownHeaderNames.Upgrade.Length, + Value = WebSocketHelpers.WebSocketUpgradeToken, + ValueLength = (uint)WebSocketHelpers.WebSocketUpgradeToken.Length + }, + new HttpHeader() + { + Name = HttpKnownHeaderNames.Host, + NameLength = (uint)HttpKnownHeaderNames.Host.Length, + Value = string.Empty, + ValueLength = 0 + }, + new HttpHeader() + { + Name = HttpKnownHeaderNames.SecWebSocketVersion, + NameLength = (uint)HttpKnownHeaderNames.SecWebSocketVersion.Length, + Value = SupportedVersion, + ValueLength = (uint)SupportedVersion.Length + }, + new HttpHeader() + { + Name = HttpKnownHeaderNames.SecWebSocketKey, + NameLength = (uint)HttpKnownHeaderNames.SecWebSocketKey.Length, + Value = DummyWebsocketKeyBase64, + ValueLength = (uint)DummyWebsocketKeyBase64.Length + } + }; + } + } + + internal static string SupportedVersion + { + get + { + if (WebSocketDllHandle.IsInvalid) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + return PrivateSupportedVersion; + } + } + + internal static bool IsSupported + { + get + { + return !WebSocketDllHandle.IsInvalid; + } + } + + internal static string GetSupportedVersion() + { + if (WebSocketDllHandle.IsInvalid) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + SafeWebSocketHandle webSocketHandle = null; + try + { + int errorCode = WebSocketCreateClientHandle_Raw(null, 0, out webSocketHandle); + ThrowOnError(errorCode); + + if (webSocketHandle == null || + webSocketHandle.IsInvalid) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + IntPtr additionalHeadersPtr; + uint additionalHeaderCount; + + errorCode = WebSocketBeginClientHandshake_Raw(webSocketHandle, + IntPtr.Zero, + 0, + IntPtr.Zero, + 0, + InitialClientRequestHeaders, + (uint)InitialClientRequestHeaders.Length, + out additionalHeadersPtr, + out additionalHeaderCount); + ThrowOnError(errorCode); + + HttpHeader[] additionalHeaders = MarshalHttpHeaders(additionalHeadersPtr, (int)additionalHeaderCount); + + string version = null; + foreach (HttpHeader header in additionalHeaders) + { + if (string.Compare(header.Name, + HttpKnownHeaderNames.SecWebSocketVersion, + StringComparison.OrdinalIgnoreCase) == 0) + { + version = header.Value; + break; + } + } + Contract.Assert(version != null, "'version' MUST NOT be NULL."); + + return version; + } + finally + { + if (webSocketHandle != null) + { + webSocketHandle.Dispose(); + } + } + } + + internal static void WebSocketCreateClientHandle(Property[] properties, + out SafeWebSocketHandle webSocketHandle) + { + uint propertyCount = properties == null ? 0 : (uint)properties.Length; + + if (WebSocketDllHandle.IsInvalid) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + int errorCode = WebSocketCreateClientHandle_Raw(properties, propertyCount, out webSocketHandle); + ThrowOnError(errorCode); + + if (webSocketHandle == null || + webSocketHandle.IsInvalid) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + IntPtr additionalHeadersPtr; + uint additionalHeaderCount; + + // Currently the WSPC doesn't allow to initiate a data session + // without also being involved in the http handshake + // There is no information whatsoever, which is needed by the + // WSPC for parsing WebSocket frames from the HTTP handshake + // In the managed implementation the HTTP header handling + // will be done using the managed HTTP stack and we will + // just fake an HTTP handshake for the WSPC calling + // WebSocketBeginClientHandshake and WebSocketEndClientHandshake + // with statically defined dummy headers. + errorCode = WebSocketBeginClientHandshake_Raw(webSocketHandle, + IntPtr.Zero, + 0, + IntPtr.Zero, + 0, + InitialClientRequestHeaders, + (uint)InitialClientRequestHeaders.Length, + out additionalHeadersPtr, + out additionalHeaderCount); + + ThrowOnError(errorCode); + + HttpHeader[] additionalHeaders = MarshalHttpHeaders(additionalHeadersPtr, (int)additionalHeaderCount); + + string key = null; + foreach (HttpHeader header in additionalHeaders) + { + if (string.Compare(header.Name, + HttpKnownHeaderNames.SecWebSocketKey, + StringComparison.OrdinalIgnoreCase) == 0) + { + key = header.Value; + break; + } + } + Contract.Assert(key != null, "'key' MUST NOT be NULL."); + + string acceptValue = WebSocketHelpers.GetSecWebSocketAcceptString(key); + HttpHeader[] responseHeaders = new HttpHeader[] + { + new HttpHeader() + { + Name = HttpKnownHeaderNames.Connection, + NameLength = (uint)HttpKnownHeaderNames.Connection.Length, + Value = HttpKnownHeaderNames.Upgrade, + ValueLength = (uint)HttpKnownHeaderNames.Upgrade.Length + }, + new HttpHeader() + { + Name = HttpKnownHeaderNames.Upgrade, + NameLength = (uint)HttpKnownHeaderNames.Upgrade.Length, + Value = WebSocketHelpers.WebSocketUpgradeToken, + ValueLength = (uint)WebSocketHelpers.WebSocketUpgradeToken.Length + }, + new HttpHeader() + { + Name = HttpKnownHeaderNames.SecWebSocketAccept, + NameLength = (uint)HttpKnownHeaderNames.SecWebSocketAccept.Length, + Value = acceptValue, + ValueLength = (uint)acceptValue.Length + } + }; + + errorCode = WebSocketEndClientHandshake_Raw(webSocketHandle, + responseHeaders, + (uint)responseHeaders.Length, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero); + + ThrowOnError(errorCode); + + Contract.Assert(webSocketHandle != null, "'webSocketHandle' MUST NOT be NULL at this point."); + } + + internal static void WebSocketCreateServerHandle(Property[] properties, + int propertyCount, + out SafeWebSocketHandle webSocketHandle) + { + Contract.Assert(propertyCount >= 0, "'propertyCount' MUST NOT be negative."); + Contract.Assert((properties == null && propertyCount == 0) || + (properties != null && propertyCount == properties.Length), + "'propertyCount' MUST MATCH 'properties.Length'."); + + if (WebSocketDllHandle.IsInvalid) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + int errorCode = WebSocketCreateServerHandle_Raw(properties, (uint)propertyCount, out webSocketHandle); + ThrowOnError(errorCode); + + if (webSocketHandle == null || + webSocketHandle.IsInvalid) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + IntPtr responseHeadersPtr; + uint responseHeaderCount; + + // Currently the WSPC doesn't allow to initiate a data session + // without also being involved in the http handshake + // There is no information whatsoever, which is needed by the + // WSPC for parsing WebSocket frames from the HTTP handshake + // In the managed implementation the HTTP header handling + // will be done using the managed HTTP stack and we will + // just fake an HTTP handshake for the WSPC calling + // WebSocketBeginServerHandshake and WebSocketEndServerHandshake + // with statically defined dummy headers. + errorCode = WebSocketBeginServerHandshake_Raw(webSocketHandle, + IntPtr.Zero, + IntPtr.Zero, + 0, + ServerFakeRequestHeaders, + (uint)ServerFakeRequestHeaders.Length, + out responseHeadersPtr, + out responseHeaderCount); + + ThrowOnError(errorCode); + + HttpHeader[] responseHeaders = MarshalHttpHeaders(responseHeadersPtr, (int)responseHeaderCount); + errorCode = WebSocketEndServerHandshake_Raw(webSocketHandle); + + ThrowOnError(errorCode); + + Contract.Assert(webSocketHandle != null, "'webSocketHandle' MUST NOT be NULL at this point."); + } + + internal static void WebSocketAbortHandle(SafeHandle webSocketHandle) + { + Contract.Assert(webSocketHandle != null && !webSocketHandle.IsInvalid, + "'webSocketHandle' MUST NOT be NULL or INVALID."); + + WebSocketAbortHandle_Raw(webSocketHandle); + + DrainActionQueue(webSocketHandle, ActionQueue.Send); + DrainActionQueue(webSocketHandle, ActionQueue.Receive); + } + + internal static void WebSocketDeleteHandle(IntPtr webSocketPtr) + { + Contract.Assert(webSocketPtr != IntPtr.Zero, "'webSocketPtr' MUST NOT be IntPtr.Zero."); + WebSocketDeleteHandle_Raw(webSocketPtr); + } + + internal static void WebSocketSend(WebSocketBase webSocket, + BufferType bufferType, + Buffer buffer) + { + Contract.Assert(webSocket != null, + "'webSocket' MUST NOT be NULL or INVALID."); + Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, + "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); + + ThrowIfSessionHandleClosed(webSocket); + + int errorCode; + try + { + errorCode = WebSocketSend_Raw(webSocket.SessionHandle, bufferType, ref buffer, IntPtr.Zero); + } + catch (ObjectDisposedException innerException) + { + throw ConvertObjectDisposedException(webSocket, innerException); + } + + ThrowOnError(errorCode); + } + + internal static void WebSocketSendWithoutBody(WebSocketBase webSocket, + BufferType bufferType) + { + Contract.Assert(webSocket != null, + "'webSocket' MUST NOT be NULL or INVALID."); + Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, + "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); + + ThrowIfSessionHandleClosed(webSocket); + + int errorCode; + try + { + errorCode = WebSocketSendWithoutBody_Raw(webSocket.SessionHandle, bufferType, IntPtr.Zero, IntPtr.Zero); + } + catch (ObjectDisposedException innerException) + { + throw ConvertObjectDisposedException(webSocket, innerException); + } + + ThrowOnError(errorCode); + } + + internal static void WebSocketReceive(WebSocketBase webSocket) + { + Contract.Assert(webSocket != null, + "'webSocket' MUST NOT be NULL or INVALID."); + Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, + "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); + + ThrowIfSessionHandleClosed(webSocket); + + int errorCode; + try + { + errorCode = WebSocketReceive_Raw(webSocket.SessionHandle, IntPtr.Zero, IntPtr.Zero); + } + catch (ObjectDisposedException innerException) + { + throw ConvertObjectDisposedException(webSocket, innerException); + } + + ThrowOnError(errorCode); + } + + internal static void WebSocketGetAction(WebSocketBase webSocket, + ActionQueue actionQueue, + Buffer[] dataBuffers, + ref uint dataBufferCount, + out Action action, + out BufferType bufferType, + out IntPtr actionContext) + { + Contract.Assert(webSocket != null, + "'webSocket' MUST NOT be NULL or INVALID."); + Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, + "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); + Contract.Assert(dataBufferCount >= 0, "'dataBufferCount' MUST NOT be negative."); + Contract.Assert((dataBuffers == null && dataBufferCount == 0) || + (dataBuffers != null && dataBufferCount == dataBuffers.Length), + "'dataBufferCount' MUST MATCH 'dataBuffers.Length'."); + + action = Action.NoAction; + bufferType = BufferType.None; + actionContext = IntPtr.Zero; + + IntPtr dummy; + ThrowIfSessionHandleClosed(webSocket); + + int errorCode; + try + { + errorCode = WebSocketGetAction_Raw(webSocket.SessionHandle, + actionQueue, + dataBuffers, + ref dataBufferCount, + out action, + out bufferType, + out dummy, + out actionContext); + } + catch (ObjectDisposedException innerException) + { + throw ConvertObjectDisposedException(webSocket, innerException); + } + ThrowOnError(errorCode); + + webSocket.ValidateNativeBuffers(action, bufferType, dataBuffers, dataBufferCount); + + Contract.Assert(dataBufferCount >= 0); + Contract.Assert((dataBufferCount == 0 && dataBuffers == null) || + (dataBufferCount <= dataBuffers.Length)); + } + + internal static void WebSocketCompleteAction(WebSocketBase webSocket, + IntPtr actionContext, + int bytesTransferred) + { + Contract.Assert(webSocket != null, + "'webSocket' MUST NOT be NULL or INVALID."); + Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, + "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); + Contract.Assert(actionContext != IntPtr.Zero, "'actionContext' MUST NOT be IntPtr.Zero."); + Contract.Assert(bytesTransferred >= 0, "'bytesTransferred' MUST NOT be negative."); + + if (webSocket.SessionHandle.IsClosed) + { + return; + } + + try + { + WebSocketCompleteAction_Raw(webSocket.SessionHandle, actionContext, (uint)bytesTransferred); + } + catch (ObjectDisposedException) + { + } + } + + internal static TimeSpan WebSocketGetDefaultKeepAliveInterval() + { + uint result = 0; + uint size = sizeof(uint); + int errorCode = WebSocketGetGlobalProperty_Raw(PropertyType.KeepAliveInterval, ref result, ref size); + if (!Succeeded(errorCode)) + { + Contract.Assert(errorCode == 0, "errorCode: " + errorCode); + return Timeout.InfiniteTimeSpan; + } + return TimeSpan.FromMilliseconds(result); + } + + private static void DrainActionQueue(SafeHandle webSocketHandle, ActionQueue actionQueue) + { + Contract.Assert(webSocketHandle != null && !webSocketHandle.IsInvalid, + "'webSocketHandle' MUST NOT be NULL or INVALID."); + + IntPtr actionContext; + IntPtr dummy; + Action action; + BufferType bufferType; + + while (true) + { + Buffer[] dataBuffers = new Buffer[1]; + uint dataBufferCount = 1; + int errorCode = WebSocketGetAction_Raw(webSocketHandle, + actionQueue, + dataBuffers, + ref dataBufferCount, + out action, + out bufferType, + out dummy, + out actionContext); + + if (!Succeeded(errorCode)) + { + Contract.Assert(errorCode == 0, "'errorCode' MUST be 0."); + return; + } + + if (action == Action.NoAction) + { + return; + } + + WebSocketCompleteAction_Raw(webSocketHandle, actionContext, 0); + } + } + + private static void MarshalAndVerifyHttpHeader(IntPtr httpHeaderPtr, + ref HttpHeader httpHeader) + { + Contract.Assert(httpHeaderPtr != IntPtr.Zero, "'currentHttpHeaderPtr' MUST NOT be IntPtr.Zero."); + + IntPtr httpHeaderNamePtr = Marshal.ReadIntPtr(httpHeaderPtr); + IntPtr lengthPtr = IntPtr.Add(httpHeaderPtr, IntPtr.Size); + int length = Marshal.ReadInt32(lengthPtr); + Contract.Assert(length >= 0, "'length' MUST NOT be negative."); + + if (httpHeaderNamePtr != IntPtr.Zero) + { + httpHeader.Name = Marshal.PtrToStringAnsi(httpHeaderNamePtr, length); + } + + if ((httpHeader.Name == null && length != 0) || + (httpHeader.Name != null && length != httpHeader.Name.Length)) + { + Contract.Assert(false, "The length of 'httpHeader.Name' MUST MATCH 'length'."); + throw new AccessViolationException(); + } + + // structure of HttpHeader: + // Name = string* + // NameLength = uint* + // Value = string* + // ValueLength = uint* + // NOTE - All fields in the object are pointers to the actual value, hence the use of + // n * IntPtr.Size to get to the correct place in the object. + int valueOffset = 2 * IntPtr.Size; + int lengthOffset = 3 * IntPtr.Size; + + IntPtr httpHeaderValuePtr = + Marshal.ReadIntPtr(IntPtr.Add(httpHeaderPtr, valueOffset)); + lengthPtr = IntPtr.Add(httpHeaderPtr, lengthOffset); + length = Marshal.ReadInt32(lengthPtr); + httpHeader.Value = Marshal.PtrToStringAnsi(httpHeaderValuePtr, (int)length); + + if ((httpHeader.Value == null && length != 0) || + (httpHeader.Value != null && length != httpHeader.Value.Length)) + { + Contract.Assert(false, "The length of 'httpHeader.Value' MUST MATCH 'length'."); + throw new AccessViolationException(); + } + } + + private static HttpHeader[] MarshalHttpHeaders(IntPtr nativeHeadersPtr, + int nativeHeaderCount) + { + Contract.Assert(nativeHeaderCount >= 0, "'nativeHeaderCount' MUST NOT be negative."); + Contract.Assert(nativeHeadersPtr != IntPtr.Zero || nativeHeaderCount == 0, + "'nativeHeaderCount' MUST be 0."); + + HttpHeader[] httpHeaders = new HttpHeader[nativeHeaderCount]; + + // structure of HttpHeader: + // Name = string* + // NameLength = uint* + // Value = string* + // ValueLength = uint* + // NOTE - All fields in the object are pointers to the actual value, hence the use of + // 4 * IntPtr.Size to get to the next header. + int httpHeaderStructSize = 4 * IntPtr.Size; + + for (int i = 0; i < nativeHeaderCount; i++) + { + int offset = httpHeaderStructSize * i; + IntPtr currentHttpHeaderPtr = IntPtr.Add(nativeHeadersPtr, offset); + MarshalAndVerifyHttpHeader(currentHttpHeaderPtr, ref httpHeaders[i]); + } + + Contract.Assert(httpHeaders != null); + Contract.Assert(httpHeaders.Length == nativeHeaderCount); + + return httpHeaders; + } + + public static bool Succeeded(int hr) + { + return (hr >= 0); + } + + private static void ThrowOnError(int errorCode) + { + if (Succeeded(errorCode)) + { + return; + } + + throw new WebSocketException(errorCode); + } + + private static void ThrowIfSessionHandleClosed(WebSocketBase webSocket) + { + if (webSocket.SessionHandle.IsClosed) + { + throw new WebSocketException(WebSocketError.InvalidState, + SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, webSocket.GetType().FullName, webSocket.State)); + } + } + + private static WebSocketException ConvertObjectDisposedException(WebSocketBase webSocket, ObjectDisposedException innerException) + { + return new WebSocketException(WebSocketError.InvalidState, + SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, webSocket.GetType().FullName, webSocket.State), + innerException); + } + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketCreateClientHandle", ExactSpelling = true)] + private static extern int WebSocketCreateClientHandle_Raw( + [In]Property[] properties, + [In] uint propertyCount, + [Out] out SafeWebSocketHandle webSocketHandle); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketBeginClientHandshake", ExactSpelling = true)] + private static extern int WebSocketBeginClientHandshake_Raw( + [In] SafeHandle webSocketHandle, + [In] IntPtr subProtocols, + [In] uint subProtocolCount, + [In] IntPtr extensions, + [In] uint extensionCount, + [In] HttpHeader[] initialHeaders, + [In] uint initialHeaderCount, + [Out] out IntPtr additionalHeadersPtr, + [Out] out uint additionalHeaderCount); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketEndClientHandshake", ExactSpelling = true)] + private static extern int WebSocketEndClientHandshake_Raw([In] SafeHandle webSocketHandle, + [In] HttpHeader[] responseHeaders, + [In] uint responseHeaderCount, + [In, Out] IntPtr selectedExtensions, + [In] IntPtr selectedExtensionCount, + [In] IntPtr selectedSubProtocol); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketBeginServerHandshake", ExactSpelling = true)] + private static extern int WebSocketBeginServerHandshake_Raw( + [In] SafeHandle webSocketHandle, + [In] IntPtr subProtocol, + [In] IntPtr extensions, + [In] uint extensionCount, + [In] HttpHeader[] requestHeaders, + [In] uint requestHeaderCount, + [Out] out IntPtr responseHeadersPtr, + [Out] out uint responseHeaderCount); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketEndServerHandshake", ExactSpelling = true)] + private static extern int WebSocketEndServerHandshake_Raw([In] SafeHandle webSocketHandle); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketCreateServerHandle", ExactSpelling = true)] + private static extern int WebSocketCreateServerHandle_Raw( + [In]Property[] properties, + [In] uint propertyCount, + [Out] out SafeWebSocketHandle webSocketHandle); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketAbortHandle", ExactSpelling = true)] + private static extern void WebSocketAbortHandle_Raw( + [In] SafeHandle webSocketHandle); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketDeleteHandle", ExactSpelling = true)] + private static extern void WebSocketDeleteHandle_Raw( + [In] IntPtr webSocketHandle); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketSend", ExactSpelling = true)] + private static extern int WebSocketSend_Raw( + [In] SafeHandle webSocketHandle, + [In] BufferType bufferType, + [In] ref Buffer buffer, + [In] IntPtr applicationContext); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketSend", ExactSpelling = true)] + private static extern int WebSocketSendWithoutBody_Raw( + [In] SafeHandle webSocketHandle, + [In] BufferType bufferType, + [In] IntPtr buffer, + [In] IntPtr applicationContext); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketReceive", ExactSpelling = true)] + private static extern int WebSocketReceive_Raw( + [In] SafeHandle webSocketHandle, + [In] IntPtr buffers, + [In] IntPtr applicationContext); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketGetAction", ExactSpelling = true)] + private static extern int WebSocketGetAction_Raw( + [In] SafeHandle webSocketHandle, + [In] ActionQueue actionQueue, + [In, Out] Buffer[] dataBuffers, + [In, Out] ref uint dataBufferCount, + [Out] out Action action, + [Out] out BufferType bufferType, + [Out] out IntPtr applicationContext, + [Out] out IntPtr actionContext); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketCompleteAction", ExactSpelling = true)] + private static extern void WebSocketCompleteAction_Raw( + [In] SafeHandle webSocketHandle, + [In] IntPtr actionContext, + [In] uint bytesTransferred); + + [DllImport(WEBSOCKET, EntryPoint = "WebSocketGetGlobalProperty", ExactSpelling = true)] + private static extern int WebSocketGetGlobalProperty_Raw( + [In] PropertyType property, + [In, Out] ref uint value, + [In, Out] ref uint size); + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs b/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs new file mode 100644 index 0000000000..a11c34488d --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.WebSockets +{ + using WebSocketCloseAsync = + Func; + using WebSocketReceiveAsync = + Func /* data */, + CancellationToken /* cancel */, + Task>>; + using WebSocketReceiveTuple = + Tuple; + using WebSocketSendAsync = + Func /* data */, + int /* messageType */, + bool /* endOfMessage */, + CancellationToken /* cancel */, + Task>; + + internal class OwinWebSocketWrapper + { + private readonly WebSocket _webSocket; + private readonly IDictionary _environment; + private readonly CancellationToken _cancellationToken; + + internal OwinWebSocketWrapper(WebSocket webSocket, CancellationToken ct) + { + _webSocket = webSocket; + _cancellationToken = ct; + + _environment = new Dictionary(); + _environment[Constants.WebSocketSendAsyncKey] = new WebSocketSendAsync(SendAsync); + _environment[Constants.WebSocketReceiveAyncKey] = new WebSocketReceiveAsync(ReceiveAsync); + _environment[Constants.WebSocketCloseAsyncKey] = new WebSocketCloseAsync(CloseAsync); + _environment[Constants.WebSocketCallCancelledKey] = ct; + _environment[Constants.WebSocketVersionKey] = Constants.WebSocketVersion; + } + + internal IDictionary Environment + { + get { return _environment; } + } + + internal Task SendAsync(ArraySegment buffer, int messageType, bool endOfMessage, CancellationToken cancel) + { + // Remap close messages to CloseAsync. System.Net.WebSockets.WebSocket.SendAsync does not allow close messages. + if (messageType == 0x8) + { + return RedirectSendToCloseAsync(buffer, cancel); + } + else if (messageType == 0x9 || messageType == 0xA) + { + // Ping & Pong, not allowed by the underlying APIs, silently discard. + return Task.FromResult(0); + } + + return _webSocket.SendAsync(buffer, (WebSocketMessageType)messageType, endOfMessage, cancel); + } + + internal async Task ReceiveAsync(ArraySegment buffer, CancellationToken cancel) + { + WebSocketReceiveResult nativeResult = await _webSocket.ReceiveAsync(buffer, cancel); + + if (nativeResult.MessageType == WebSocketMessageType.Close) + { + _environment[Constants.WebSocketCloseStatusKey] = (int)(nativeResult.CloseStatus ?? WebSocketCloseStatus.NormalClosure); + _environment[Constants.WebSocketCloseDescriptionKey] = nativeResult.CloseStatusDescription ?? string.Empty; + } + + return new WebSocketReceiveTuple( + (int)nativeResult.MessageType, + nativeResult.EndOfMessage, + nativeResult.Count); + } + + internal Task CloseAsync(int status, string description, CancellationToken cancel) + { + return _webSocket.CloseOutputAsync((WebSocketCloseStatus)status, description, cancel); + } + + private Task RedirectSendToCloseAsync(ArraySegment buffer, CancellationToken cancel) + { + if (buffer.Array == null || buffer.Count == 0) + { + return CloseAsync(1000, string.Empty, cancel); + } + else if (buffer.Count >= 2) + { + // Unpack the close message. + int statusCode = + (buffer.Array[buffer.Offset] << 8) + | buffer.Array[buffer.Offset + 1]; + string description = Encoding.UTF8.GetString(buffer.Array, buffer.Offset + 2, buffer.Count - 2); + + return CloseAsync(statusCode, description, cancel); + } + else + { + throw new ArgumentOutOfRangeException("buffer"); + } + } + + internal async Task CleanupAsync() + { + switch (_webSocket.State) + { + case WebSocketState.Closed: // Closed gracefully, no action needed. + case WebSocketState.Aborted: // Closed abortively, no action needed. + break; + case WebSocketState.CloseReceived: + // Echo what the client said, if anything. + await _webSocket.CloseAsync(_webSocket.CloseStatus ?? WebSocketCloseStatus.NormalClosure, + _webSocket.CloseStatusDescription ?? string.Empty, _cancellationToken); + break; + case WebSocketState.Open: + case WebSocketState.CloseSent: // No close received, abort so we don't have to drain the pipe. + _webSocket.Abort(); + break; + default: + throw new ArgumentOutOfRangeException("state", _webSocket.State, string.Empty); + } + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..1abade9a33 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.AspNet.WebSockets")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.AspNet.WebSockets")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1f471909-581f-4060-a147-430891e9c3c1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("0.5")] +[assembly: AssemblyVersion("0.5")] +[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs b/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs new file mode 100644 index 0000000000..f23d13af54 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.IO; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.WebSockets +{ + internal sealed class ServerWebSocket : WebSocketBase + { + private readonly SafeHandle _sessionHandle; + private readonly UnsafeNativeMethods.WebSocketProtocolComponent.Property[] _properties; + + public ServerWebSocket(Stream innerStream, + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + : base(innerStream, subProtocol, keepAliveInterval, + WebSocketBuffer.CreateServerBuffer(internalBuffer, receiveBufferSize)) + { + _properties = this.InternalBuffer.CreateProperties(false); + _sessionHandle = this.CreateWebSocketHandle(); + + if (_sessionHandle == null || _sessionHandle.IsInvalid) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + StartKeepAliveTimer(); + } + + internal override SafeHandle SessionHandle + { + get + { + Contract.Assert(_sessionHandle != null, "'m_SessionHandle MUST NOT be NULL."); + return _sessionHandle; + } + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", + Justification = "No arbitrary data controlled by PT code is leaking into native code.")] + private SafeHandle CreateWebSocketHandle() + { + Contract.Assert(_properties != null, "'m_Properties' MUST NOT be NULL."); + SafeWebSocketHandle sessionHandle; + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCreateServerHandle(_properties, + _properties.Length, + out sessionHandle); + Contract.Assert(sessionHandle != null, "'sessionHandle MUST NOT be NULL."); + + return sessionHandle; + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/WebSocket.cs b/src/Microsoft.AspNet.WebSockets/WebSocket.cs new file mode 100644 index 0000000000..f75e50a3c6 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocket.cs @@ -0,0 +1,124 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.WebSockets +{ + public abstract class WebSocket : IDisposable + { + private static TimeSpan? defaultKeepAliveInterval; + + public abstract WebSocketCloseStatus? CloseStatus { get; } + public abstract string CloseStatusDescription { get; } + public abstract string SubProtocol { get; } + public abstract WebSocketState State { get; } + + public static TimeSpan DefaultKeepAliveInterval + { + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", + Justification = "This is a harmless read-only operation")] + get + { + if (defaultKeepAliveInterval == null) + { + if (UnsafeNativeMethods.WebSocketProtocolComponent.IsSupported) + { + defaultKeepAliveInterval = UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketGetDefaultKeepAliveInterval(); + } + else + { + defaultKeepAliveInterval = Timeout.InfiniteTimeSpan; + } + } + return defaultKeepAliveInterval.Value; + } + } + + public static ArraySegment CreateClientBuffer(int receiveBufferSize, int sendBufferSize) + { + WebSocketHelpers.ValidateBufferSizes(receiveBufferSize, sendBufferSize); + + return WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, sendBufferSize, false); + } + + public static ArraySegment CreateServerBuffer(int receiveBufferSize) + { + WebSocketHelpers.ValidateBufferSizes(receiveBufferSize, WebSocketBuffer.MinSendBufferSize); + + return WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + } + + internal static WebSocket CreateServerWebSocket(Stream innerStream, + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + { + if (!UnsafeNativeMethods.WebSocketProtocolComponent.IsSupported) + { + WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); + } + + WebSocketHelpers.ValidateInnerStream(innerStream); + WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); + WebSocketHelpers.ValidateArraySegment(internalBuffer, "internalBuffer"); + WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + + return new ServerWebSocket(innerStream, + subProtocol, + receiveBufferSize, + keepAliveInterval, + internalBuffer); + } + + public abstract void Abort(); + public abstract Task CloseAsync(WebSocketCloseStatus closeStatus, + string statusDescription, + CancellationToken cancellationToken); + public abstract Task CloseOutputAsync(WebSocketCloseStatus closeStatus, + string statusDescription, + CancellationToken cancellationToken); + [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "This rule is outdated")] + public abstract void Dispose(); + public abstract Task ReceiveAsync(ArraySegment buffer, + CancellationToken cancellationToken); + public abstract Task SendAsync(ArraySegment buffer, + WebSocketMessageType messageType, + bool endOfMessage, + CancellationToken cancellationToken); + + protected static void ThrowOnInvalidState(WebSocketState state, params WebSocketState[] validStates) + { + string validStatesText = string.Empty; + + if (validStates != null && validStates.Length > 0) + { + foreach (WebSocketState currentState in validStates) + { + if (state == currentState) + { + return; + } + } + + validStatesText = string.Join(", ", validStates); + } + + throw new WebSocketException(SR.GetString(SR.net_WebSockets_InvalidState, state, validStatesText)); + } + + protected static bool IsStateTerminal(WebSocketState state) + { + return state == WebSocketState.Closed || + state == WebSocketState.Aborted; + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs b/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs new file mode 100644 index 0000000000..3e3b798396 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs @@ -0,0 +1,2481 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.WebSockets +{ + internal abstract class WebSocketBase : WebSocket, IDisposable + { + // private static volatile bool s_LoggingEnabled; + + private readonly OutstandingOperationHelper _closeOutstandingOperationHelper; + private readonly OutstandingOperationHelper _closeOutputOutstandingOperationHelper; + private readonly OutstandingOperationHelper _receiveOutstandingOperationHelper; + private readonly OutstandingOperationHelper _sendOutstandingOperationHelper; + private readonly Stream _innerStream; + private readonly IWebSocketStream _innerStreamAsWebSocketStream; + private readonly string _subProtocol; + + // We are not calling Dispose method on this object in Cleanup method to avoid a race condition while one thread is calling disposing on + // this object and another one is still using WaitAsync. According to Dev11 358715, this should be fine as long as we are not accessing the + // AvailableWaitHandle on this SemaphoreSlim object. + private readonly SemaphoreSlim _sendFrameThrottle; + // locking m_ThisLock protects access to + // - State + // - m_CloseStack + // - m_CloseAsyncStartedReceive + // - m_CloseReceivedTaskCompletionSource + // - m_CloseNetworkConnectionTask + private readonly object _thisLock; + private readonly WebSocketBuffer _internalBuffer; + private readonly KeepAliveTracker _keepAliveTracker; + +#if DEBUG + private volatile string _closeStack; +#endif + + private volatile bool _cleanedUp; + private volatile TaskCompletionSource _closeReceivedTaskCompletionSource; + private volatile Task _closeOutputTask; + private volatile bool _isDisposed; + private volatile Task _closeNetworkConnectionTask; + private volatile bool _closeAsyncStartedReceive; + private volatile WebSocketState _state; + private volatile Task _keepAliveTask; + private volatile WebSocketOperation.ReceiveOperation _receiveOperation; + private volatile WebSocketOperation.SendOperation _sendOperation; + private volatile WebSocketOperation.SendOperation _keepAliveOperation; + private volatile WebSocketOperation.CloseOutputOperation _closeOutputOperation; + private WebSocketCloseStatus? _closeStatus; + private string _closeStatusDescription; + private int _receiveState; + private Exception _pendingException; + + protected WebSocketBase(Stream innerStream, + string subProtocol, + TimeSpan keepAliveInterval, + WebSocketBuffer internalBuffer) + { + Contract.Assert(internalBuffer != null, "'internalBuffer' MUST NOT be NULL."); + WebSocketHelpers.ValidateInnerStream(innerStream); + WebSocketHelpers.ValidateOptions(subProtocol, internalBuffer.ReceiveBufferSize, + internalBuffer.SendBufferSize, keepAliveInterval); + + // s_LoggingEnabled = Logging.On && Logging.WebSockets.Switch.ShouldTrace(TraceEventType.Critical); + string parameters = string.Empty; + /* + if (s_LoggingEnabled) + { + parameters = string.Format(CultureInfo.InvariantCulture, + "ReceiveBufferSize: {0}, SendBufferSize: {1}, Protocols: {2}, KeepAliveInterval: {3}, innerStream: {4}, internalBuffer: {5}", + internalBuffer.ReceiveBufferSize, + internalBuffer.SendBufferSize, + subProtocol, + keepAliveInterval, + Logging.GetObjectLogHash(innerStream), + Logging.GetObjectLogHash(internalBuffer)); + + Logging.Enter(Logging.WebSockets, this, Methods.Initialize, parameters); + } + */ + _thisLock = new object(); + + try + { + _innerStream = innerStream; + _internalBuffer = internalBuffer; + /*if (s_LoggingEnabled) + { + Logging.Associate(Logging.WebSockets, this, m_InnerStream); + Logging.Associate(Logging.WebSockets, this, m_InternalBuffer); + }*/ + + _closeOutstandingOperationHelper = new OutstandingOperationHelper(); + _closeOutputOutstandingOperationHelper = new OutstandingOperationHelper(); + _receiveOutstandingOperationHelper = new OutstandingOperationHelper(); + _sendOutstandingOperationHelper = new OutstandingOperationHelper(); + _state = WebSocketState.Open; + _subProtocol = subProtocol; + _sendFrameThrottle = new SemaphoreSlim(1, 1); + _closeStatus = null; + _closeStatusDescription = null; + _innerStreamAsWebSocketStream = innerStream as IWebSocketStream; + if (_innerStreamAsWebSocketStream != null) + { + _innerStreamAsWebSocketStream.SwitchToOpaqueMode(this); + } + _keepAliveTracker = KeepAliveTracker.Create(keepAliveInterval); + } + finally + { + /*if (s_LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.Initialize, parameters); + }*/ + } + } + /* + internal static bool LoggingEnabled + { + get + { + return s_LoggingEnabled; + } + } + */ + public override WebSocketState State + { + get + { + Contract.Assert(_state != WebSocketState.None, "'m_State' MUST NOT be 'WebSocketState.None'."); + return _state; + } + } + + public override string SubProtocol + { + get + { + return _subProtocol; + } + } + + public override WebSocketCloseStatus? CloseStatus + { + get + { + return _closeStatus; + } + } + + public override string CloseStatusDescription + { + get + { + return _closeStatusDescription; + } + } + + internal WebSocketBuffer InternalBuffer + { + get + { + Contract.Assert(_internalBuffer != null, "'m_InternalBuffer' MUST NOT be NULL."); + return _internalBuffer; + } + } + + protected void StartKeepAliveTimer() + { + _keepAliveTracker.StartTimer(this); + } + + // locking SessionHandle protects access to + // - WSPC (WebSocketProtocolComponent) + // - m_KeepAliveTask + // - m_CloseOutputTask + // - m_LastSendActivity + internal abstract SafeHandle SessionHandle { get; } + + // MultiThreading: ThreadSafe; At most one outstanding call to ReceiveAsync is allowed + public override Task ReceiveAsync(ArraySegment buffer, + CancellationToken cancellationToken) + { + WebSocketHelpers.ValidateArraySegment(buffer, "buffer"); + return ReceiveAsyncCore(buffer, cancellationToken); + } + + private async Task ReceiveAsyncCore(ArraySegment buffer, + CancellationToken cancellationToken) + { + Contract.Assert(buffer.Array != null); + /* + if (s_LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, this, Methods.ReceiveAsync, string.Empty); + } + */ + WebSocketReceiveResult receiveResult; + try + { + ThrowIfPendingException(); + ThrowIfDisposed(); + ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseSent); + + bool ownsCancellationTokenSource = false; + CancellationToken linkedCancellationToken = CancellationToken.None; + try + { + ownsCancellationTokenSource = _receiveOutstandingOperationHelper.TryStartOperation(cancellationToken, + out linkedCancellationToken); + if (!ownsCancellationTokenSource) + { + lock (_thisLock) + { + if (_closeAsyncStartedReceive) + { + throw new InvalidOperationException( + SR.GetString(SR.net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync, Methods.CloseAsync, Methods.CloseOutputAsync)); + } + + throw new InvalidOperationException( + SR.GetString(SR.net_Websockets_AlreadyOneOutstandingOperation, Methods.ReceiveAsync)); + } + } + + EnsureReceiveOperation(); + receiveResult = await _receiveOperation.Process(buffer, linkedCancellationToken).SuppressContextFlow(); + /* + if (s_LoggingEnabled && receiveResult.Count > 0) + { + Logging.Dump(Logging.WebSockets, + this, + Methods.ReceiveAsync, + buffer.Array, + buffer.Offset, + receiveResult.Count); + }*/ + } + catch (Exception exception) + { + bool aborted = linkedCancellationToken.IsCancellationRequested; + Abort(); + ThrowIfConvertibleException(Methods.ReceiveAsync, exception, cancellationToken, aborted); + throw; + } + finally + { + _receiveOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); + } + } + finally + {/* + if (s_LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.ReceiveAsync, string.Empty); + }*/ + } + + return receiveResult; + } + + // MultiThreading: ThreadSafe; At most one outstanding call to SendAsync is allowed + public override Task SendAsync(ArraySegment buffer, + WebSocketMessageType messageType, + bool endOfMessage, + CancellationToken cancellationToken) + { + if (messageType != WebSocketMessageType.Binary && + messageType != WebSocketMessageType.Text) + { + throw new ArgumentException(SR.GetString(SR.net_WebSockets_Argument_InvalidMessageType, + messageType, + Methods.SendAsync, + WebSocketMessageType.Binary, + WebSocketMessageType.Text, + Methods.CloseOutputAsync), + "messageType"); + } + + WebSocketHelpers.ValidateArraySegment(buffer, "buffer"); + + return SendAsyncCore(buffer, messageType, endOfMessage, cancellationToken); + } + + private async Task SendAsyncCore(ArraySegment buffer, + WebSocketMessageType messageType, + bool endOfMessage, + CancellationToken cancellationToken) + { + Contract.Assert(messageType == WebSocketMessageType.Binary || messageType == WebSocketMessageType.Text, + "'messageType' MUST be either 'WebSocketMessageType.Binary' or 'WebSocketMessageType.Text'."); + Contract.Assert(buffer.Array != null); + + string inputParameter = string.Empty; + /*if (s_LoggingEnabled) + { + inputParameter = string.Format(CultureInfo.InvariantCulture, + "messageType: {0}, endOfMessage: {1}", + messageType, + endOfMessage); + Logging.Enter(Logging.WebSockets, this, Methods.SendAsync, inputParameter); + }*/ + + try + { + ThrowIfPendingException(); + ThrowIfDisposed(); + ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived); + bool ownsCancellationTokenSource = false; + CancellationToken linkedCancellationToken = CancellationToken.None; + + try + { + while (!(ownsCancellationTokenSource = _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken))) + { + Task keepAliveTask; + + lock (SessionHandle) + { + keepAliveTask = _keepAliveTask; + + if (keepAliveTask == null) + { + // Check whether there is still another outstanding send operation + // Potentially the keepAlive operation has completed before this thread + // was able to enter the SessionHandle-lock. + _sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); + if (ownsCancellationTokenSource = _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken)) + { + break; + } + else + { + throw new InvalidOperationException( + SR.GetString(SR.net_Websockets_AlreadyOneOutstandingOperation, Methods.SendAsync)); + } + } + } + + await keepAliveTask.SuppressContextFlow(); + ThrowIfPendingException(); + + _sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); + } + /* + if (s_LoggingEnabled && buffer.Count > 0) + { + Logging.Dump(Logging.WebSockets, + this, + Methods.SendAsync, + buffer.Array, + buffer.Offset, + buffer.Count); + }*/ + + int position = buffer.Offset; + + EnsureSendOperation(); + _sendOperation.BufferType = GetBufferType(messageType, endOfMessage); + await _sendOperation.Process(buffer, linkedCancellationToken).SuppressContextFlow(); + } + catch (Exception exception) + { + bool aborted = linkedCancellationToken.IsCancellationRequested; + Abort(); + ThrowIfConvertibleException(Methods.SendAsync, exception, cancellationToken, aborted); + throw; + } + finally + { + _sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); + } + } + finally + { + /*if (s_LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.SendAsync, inputParameter); + }*/ + } + } + + private async Task SendFrameAsync(IList> sendBuffers, CancellationToken cancellationToken) + { + bool sendFrameLockTaken = false; + try + { + await _sendFrameThrottle.WaitAsync(cancellationToken).SuppressContextFlow(); + sendFrameLockTaken = true; + + if (sendBuffers.Count > 1 && + _innerStreamAsWebSocketStream != null && + _innerStreamAsWebSocketStream.SupportsMultipleWrite) + { + await _innerStreamAsWebSocketStream.MultipleWriteAsync(sendBuffers, + cancellationToken).SuppressContextFlow(); + } + else + { + foreach (ArraySegment buffer in sendBuffers) + { + await _innerStream.WriteAsync(buffer.Array, + buffer.Offset, + buffer.Count, + cancellationToken).SuppressContextFlow(); + } + } + } + catch (ObjectDisposedException objectDisposedException) + { + throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, objectDisposedException); + } + catch (NotSupportedException notSupportedException) + { + throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, notSupportedException); + } + finally + { + if (sendFrameLockTaken) + { + _sendFrameThrottle.Release(); + } + } + } + + // MultiThreading: ThreadSafe; No-op if already in a terminal state + public override void Abort() + { + /*if (s_LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, this, Methods.Abort, string.Empty); + }*/ + + bool thisLockTaken = false; + bool sessionHandleLockTaken = false; + try + { + if (IsStateTerminal(State)) + { + return; + } + + TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + if (IsStateTerminal(State)) + { + return; + } + + _state = WebSocketState.Aborted; + +#if DEBUG + string stackTrace = new StackTrace().ToString(); + if (_closeStack == null) + { + _closeStack = stackTrace; + } + /* + if (s_LoggingEnabled) + { + string message = string.Format(CultureInfo.InvariantCulture, "Stack: {0}", stackTrace); + Logging.PrintWarning(Logging.WebSockets, this, Methods.Abort, message); + }*/ +#endif + + // Abort any outstanding IO operations. + if (SessionHandle != null && !SessionHandle.IsClosed && !SessionHandle.IsInvalid) + { + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketAbortHandle(SessionHandle); + } + + _receiveOutstandingOperationHelper.CancelIO(); + _sendOutstandingOperationHelper.CancelIO(); + _closeOutputOutstandingOperationHelper.CancelIO(); + _closeOutstandingOperationHelper.CancelIO(); + if (_innerStreamAsWebSocketStream != null) + { + _innerStreamAsWebSocketStream.Abort(); + } + CleanUp(); + } + finally + { + ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); + /*if (s_LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.Abort, string.Empty); + }*/ + } + } + + // MultiThreading: ThreadSafe; No-op if already in a terminal state + public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, + string statusDescription, + CancellationToken cancellationToken) + { + WebSocketHelpers.ValidateCloseStatus(closeStatus, statusDescription); + + return CloseOutputAsyncCore(closeStatus, statusDescription, cancellationToken); + } + + private async Task CloseOutputAsyncCore(WebSocketCloseStatus closeStatus, + string statusDescription, + CancellationToken cancellationToken) + { + string inputParameter = string.Empty; + /*if (s_LoggingEnabled) + { + inputParameter = string.Format(CultureInfo.InvariantCulture, + "closeStatus: {0}, statusDescription: {1}", + closeStatus, + statusDescription); + Logging.Enter(Logging.WebSockets, this, Methods.CloseOutputAsync, inputParameter); + }*/ + + try + { + ThrowIfPendingException(); + if (IsStateTerminal(State)) + { + return; + } + ThrowIfDisposed(); + + bool thisLockTaken = false; + bool sessionHandleLockTaken = false; + bool needToCompleteSendOperation = false; + bool ownsCloseOutputCancellationTokenSource = false; + bool ownsSendCancellationTokenSource = false; + CancellationToken linkedCancellationToken = CancellationToken.None; + try + { + TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + ThrowIfPendingException(); + ThrowIfDisposed(); + + if (IsStateTerminal(State)) + { + return; + } + + ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived); + ownsCloseOutputCancellationTokenSource = _closeOutputOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); + if (!ownsCloseOutputCancellationTokenSource) + { + Task closeOutputTask = _closeOutputTask; + + if (closeOutputTask != null) + { + ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); + await closeOutputTask.SuppressContextFlow(); + TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + } + } + else + { + needToCompleteSendOperation = true; + while (!(ownsSendCancellationTokenSource = + _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, + out linkedCancellationToken))) + { + if (_keepAliveTask != null) + { + Task keepAliveTask = _keepAliveTask; + + ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); + await keepAliveTask.SuppressContextFlow(); + TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + + ThrowIfPendingException(); + } + else + { + throw new InvalidOperationException( + SR.GetString(SR.net_Websockets_AlreadyOneOutstandingOperation, Methods.SendAsync)); + } + + _sendOutstandingOperationHelper.CompleteOperation(ownsSendCancellationTokenSource); + } + + EnsureCloseOutputOperation(); + _closeOutputOperation.CloseStatus = closeStatus; + _closeOutputOperation.CloseReason = statusDescription; + _closeOutputTask = _closeOutputOperation.Process(null, linkedCancellationToken); + + ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); + await _closeOutputTask.SuppressContextFlow(); + TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + + if (OnCloseOutputCompleted()) + { + bool callCompleteOnCloseCompleted = false; + + try + { + callCompleteOnCloseCompleted = await StartOnCloseCompleted( + thisLockTaken, sessionHandleLockTaken, linkedCancellationToken).SuppressContextFlow(); + } + catch (Exception) + { + // If an exception is thrown we know that the locks have been released, + // because we enforce IWebSocketStream.CloseNetworkConnectionAsync to yield + ResetFlagsAndTakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + throw; + } + + if (callCompleteOnCloseCompleted) + { + ResetFlagsAndTakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + FinishOnCloseCompleted(); + } + } + } + } + catch (Exception exception) + { + bool aborted = linkedCancellationToken.IsCancellationRequested; + Abort(); + ThrowIfConvertibleException(Methods.CloseOutputAsync, exception, cancellationToken, aborted); + throw; + } + finally + { + _closeOutputOutstandingOperationHelper.CompleteOperation(ownsCloseOutputCancellationTokenSource); + + if (needToCompleteSendOperation) + { + _sendOutstandingOperationHelper.CompleteOperation(ownsSendCancellationTokenSource); + } + + _closeOutputTask = null; + ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); + } + } + finally + { + /*if (s_LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.CloseOutputAsync, inputParameter); + }*/ + } + } + + // returns TRUE if the caller should also call StartOnCloseCompleted + private bool OnCloseOutputCompleted() + { + if (IsStateTerminal(State)) + { + return false; + } + + switch (State) + { + case WebSocketState.Open: + _state = WebSocketState.CloseSent; + return false; + case WebSocketState.CloseReceived: + return true; + default: + return false; + } + } + + // MultiThreading: This method has to be called under a m_ThisLock-lock + // ReturnValue: This method returns true only if CompleteOnCloseCompleted needs to be called + // If this method returns true all locks were released before starting the IO operation + // and they have to be retaken by the caller before calling CompleteOnCloseCompleted + // Exception handling: If an exception is thrown from await StartOnCloseCompleted + // it always means the locks have been released already - so the caller has to retake the + // locks in the catch-block. + // This is ensured by enforcing a Task.Yield for IWebSocketStream.CloseNetowrkConnectionAsync + private async Task StartOnCloseCompleted(bool thisLockTakenSnapshot, + bool sessionHandleLockTakenSnapshot, + CancellationToken cancellationToken) + { + Contract.Assert(thisLockTakenSnapshot, "'thisLockTakenSnapshot' MUST be 'true' at this point."); + + if (IsStateTerminal(_state)) + { + return false; + } + + _state = WebSocketState.Closed; + +#if DEBUG + if (_closeStack == null) + { + _closeStack = new StackTrace().ToString(); + } +#endif + + if (_innerStreamAsWebSocketStream != null) + { + bool thisLockTaken = thisLockTakenSnapshot; + bool sessionHandleLockTaken = sessionHandleLockTakenSnapshot; + + try + { + if (_closeNetworkConnectionTask == null) + { + _closeNetworkConnectionTask = + _innerStreamAsWebSocketStream.CloseNetworkConnectionAsync(cancellationToken); + } + + if (thisLockTaken && sessionHandleLockTaken) + { + ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); + } + else if (thisLockTaken) + { + ReleaseLock(_thisLock, ref thisLockTaken); + } + + await _closeNetworkConnectionTask.SuppressContextFlow(); + } + catch (Exception closeNetworkConnectionTaskException) + { + if (!CanHandleExceptionDuringClose(closeNetworkConnectionTaskException)) + { + ThrowIfConvertibleException(Methods.StartOnCloseCompleted, + closeNetworkConnectionTaskException, + cancellationToken, + cancellationToken.IsCancellationRequested); + throw; + } + } + } + + return true; + } + + // MultiThreading: This method has to be called under a thisLock-lock + private void FinishOnCloseCompleted() + { + CleanUp(); + } + + // MultiThreading: ThreadSafe; No-op if already in a terminal state + public override Task CloseAsync(WebSocketCloseStatus closeStatus, + string statusDescription, + CancellationToken cancellationToken) + { + WebSocketHelpers.ValidateCloseStatus(closeStatus, statusDescription); + return CloseAsyncCore(closeStatus, statusDescription, cancellationToken); + } + + private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, + string statusDescription, + CancellationToken cancellationToken) + { + string inputParameter = string.Empty; + /*if (s_LoggingEnabled) + { + inputParameter = string.Format(CultureInfo.InvariantCulture, + "closeStatus: {0}, statusDescription: {1}", + closeStatus, + statusDescription); + Logging.Enter(Logging.WebSockets, this, Methods.CloseAsync, inputParameter); + }*/ + + try + { + ThrowIfPendingException(); + if (IsStateTerminal(State)) + { + return; + } + ThrowIfDisposed(); + + bool lockTaken = false; + Monitor.Enter(_thisLock, ref lockTaken); + bool ownsCloseCancellationTokenSource = false; + CancellationToken linkedCancellationToken = CancellationToken.None; + try + { + ThrowIfPendingException(); + if (IsStateTerminal(State)) + { + return; + } + ThrowIfDisposed(); + ThrowOnInvalidState(State, + WebSocketState.Open, WebSocketState.CloseReceived, WebSocketState.CloseSent); + + Task closeOutputTask; + ownsCloseCancellationTokenSource = _closeOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); + if (ownsCloseCancellationTokenSource) + { + closeOutputTask = _closeOutputTask; + if (closeOutputTask == null && State != WebSocketState.CloseSent) + { + if (_closeReceivedTaskCompletionSource == null) + { + _closeReceivedTaskCompletionSource = new TaskCompletionSource(); + } + + closeOutputTask = CloseOutputAsync(closeStatus, + statusDescription, + linkedCancellationToken); + } + } + else + { + Contract.Assert(_closeReceivedTaskCompletionSource != null, + "'m_CloseReceivedTaskCompletionSource' MUST NOT be NULL."); + closeOutputTask = _closeReceivedTaskCompletionSource.Task; + } + + if (closeOutputTask != null) + { + ReleaseLock(_thisLock, ref lockTaken); + try + { + await closeOutputTask.SuppressContextFlow(); + } + catch (Exception closeOutputError) + { + Monitor.Enter(_thisLock, ref lockTaken); + + if (!CanHandleExceptionDuringClose(closeOutputError)) + { + ThrowIfConvertibleException(Methods.CloseOutputAsync, + closeOutputError, + cancellationToken, + linkedCancellationToken.IsCancellationRequested); + throw; + } + } + + // When closeOutputTask != null and an exception thrown from await closeOutputTask is handled, + // the lock will be taken in the catch-block. So the logic here avoids taking the lock twice. + if (!lockTaken) + { + Monitor.Enter(_thisLock, ref lockTaken); + } + } + + if (OnCloseOutputCompleted()) + { + bool callCompleteOnCloseCompleted = false; + + try + { + // linkedCancellationToken can be CancellationToken.None if ownsCloseCancellationTokenSource==false + // This is still ok because OnCloseOutputCompleted won't start any IO operation in this case + callCompleteOnCloseCompleted = await StartOnCloseCompleted( + lockTaken, false, linkedCancellationToken).SuppressContextFlow(); + } + catch (Exception) + { + // If an exception is thrown we know that the locks have been released, + // because we enforce IWebSocketStream.CloseNetworkConnectionAsync to yield + ResetFlagAndTakeLock(_thisLock, ref lockTaken); + throw; + } + + if (callCompleteOnCloseCompleted) + { + ResetFlagAndTakeLock(_thisLock, ref lockTaken); + FinishOnCloseCompleted(); + } + } + + if (IsStateTerminal(State)) + { + return; + } + + linkedCancellationToken = CancellationToken.None; + + bool ownsReceiveCancellationTokenSource = _receiveOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); + if (ownsReceiveCancellationTokenSource) + { + _closeAsyncStartedReceive = true; + ArraySegment closeMessageBuffer = + new ArraySegment(new byte[WebSocketBuffer.MinReceiveBufferSize]); + EnsureReceiveOperation(); + Task receiveAsyncTask = _receiveOperation.Process(closeMessageBuffer, + linkedCancellationToken); + ReleaseLock(_thisLock, ref lockTaken); + + WebSocketReceiveResult receiveResult = null; + try + { + receiveResult = await receiveAsyncTask.SuppressContextFlow(); + } + catch (Exception receiveException) + { + Monitor.Enter(_thisLock, ref lockTaken); + + if (!CanHandleExceptionDuringClose(receiveException)) + { + ThrowIfConvertibleException(Methods.CloseAsync, + receiveException, + cancellationToken, + linkedCancellationToken.IsCancellationRequested); + throw; + } + } + + // receiveResult is NEVER NULL if WebSocketBase.ReceiveOperation.Process completes successfully + // - but in the close code path we handle some exception if another thread was able to tranistion + // the state into Closed successfully. In this case receiveResult can be NULL and it is safe to + // skip the statements in the if-block. + if (receiveResult != null) + { + /*if (s_LoggingEnabled && receiveResult.Count > 0) + { + Logging.Dump(Logging.WebSockets, + this, + Methods.ReceiveAsync, + closeMessageBuffer.Array, + closeMessageBuffer.Offset, + receiveResult.Count); + }*/ + + if (receiveResult.MessageType != WebSocketMessageType.Close) + { + throw new WebSocketException(WebSocketError.InvalidMessageType, + SR.GetString(SR.net_WebSockets_InvalidMessageType, + typeof(WebSocket).Name + "." + Methods.CloseAsync, + typeof(WebSocket).Name + "." + Methods.CloseOutputAsync, + receiveResult.MessageType)); + } + } + } + else + { + _receiveOutstandingOperationHelper.CompleteOperation(ownsReceiveCancellationTokenSource); + ReleaseLock(_thisLock, ref lockTaken); + await _closeReceivedTaskCompletionSource.Task.SuppressContextFlow(); + } + + // When ownsReceiveCancellationTokenSource is true and an exception is thrown, the lock will be taken. + // So this logic here is to avoid taking the lock twice. + if (!lockTaken) + { + Monitor.Enter(_thisLock, ref lockTaken); + } + + if (!IsStateTerminal(State)) + { + bool ownsSendCancellationSource = false; + try + { + // We know that the CloseFrame has been sent at this point. So no Send-operation is allowed anymore and we + // can hijack the m_SendOutstandingOperationHelper to create a linkedCancellationToken + ownsSendCancellationSource = _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); + Contract.Assert(ownsSendCancellationSource, "'ownsSendCancellationSource' MUST be 'true' at this point."); + + bool callCompleteOnCloseCompleted = false; + + try + { + // linkedCancellationToken can be CancellationToken.None if ownsCloseCancellationTokenSource==false + // This is still ok because OnCloseOutputCompleted won't start any IO operation in this case + callCompleteOnCloseCompleted = await StartOnCloseCompleted( + lockTaken, false, linkedCancellationToken).SuppressContextFlow(); + } + catch (Exception) + { + // If an exception is thrown we know that the locks have been released, + // because we enforce IWebSocketStream.CloseNetworkConnectionAsync to yield + ResetFlagAndTakeLock(_thisLock, ref lockTaken); + throw; + } + + if (callCompleteOnCloseCompleted) + { + ResetFlagAndTakeLock(_thisLock, ref lockTaken); + FinishOnCloseCompleted(); + } + } + finally + { + _sendOutstandingOperationHelper.CompleteOperation(ownsSendCancellationSource); + } + } + } + catch (Exception exception) + { + bool aborted = linkedCancellationToken.IsCancellationRequested; + Abort(); + ThrowIfConvertibleException(Methods.CloseAsync, exception, cancellationToken, aborted); + throw; + } + finally + { + _closeOutstandingOperationHelper.CompleteOperation(ownsCloseCancellationTokenSource); + ReleaseLock(_thisLock, ref lockTaken); + } + } + finally + { + /*if (s_LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, this, Methods.CloseAsync, inputParameter); + }*/ + } + } + + // MultiThreading: ThreadSafe; No-op if already in a terminal state + [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_sendFrameThrottle", + Justification = "SemaphoreSlim.Dispose is not threadsafe and can cause NullRef exceptions on other threads." + + "Also according to the CLR Dev11#358715) there is no need to dispose SemaphoreSlim if the ManualResetEvent " + + "is not used.")] + public override void Dispose() + { + if (_isDisposed) + { + return; + } + + bool thisLockTaken = false; + bool sessionHandleLockTaken = false; + + try + { + TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + + if (_isDisposed) + { + return; + } + + if (!IsStateTerminal(State)) + { + Abort(); + } + else + { + CleanUp(); + } + + _isDisposed = true; + } + finally + { + ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); + } + } + + private void ResetFlagAndTakeLock(object lockObject, ref bool thisLockTaken) + { + Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); + thisLockTaken = false; + Monitor.Enter(lockObject, ref thisLockTaken); + } + + private void ResetFlagsAndTakeLocks(ref bool thisLockTaken, ref bool sessionHandleLockTaken) + { + thisLockTaken = false; + sessionHandleLockTaken = false; + TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); + } + + private void TakeLocks(ref bool thisLockTaken, ref bool sessionHandleLockTaken) + { + Contract.Assert(_thisLock != null, "'m_ThisLock' MUST NOT be NULL."); + Contract.Assert(SessionHandle != null, "'SessionHandle' MUST NOT be NULL."); + + Monitor.Enter(SessionHandle, ref sessionHandleLockTaken); + Monitor.Enter(_thisLock, ref thisLockTaken); + } + + private void ReleaseLocks(ref bool thisLockTaken, ref bool sessionHandleLockTaken) + { + Contract.Assert(_thisLock != null, "'m_ThisLock' MUST NOT be NULL."); + Contract.Assert(SessionHandle != null, "'SessionHandle' MUST NOT be NULL."); + + if (thisLockTaken || sessionHandleLockTaken) + { +#if NET45 + RuntimeHelpers.PrepareConstrainedRegions(); +#endif + try + { + } + finally + { + if (thisLockTaken) + { + Monitor.Exit(_thisLock); + thisLockTaken = false; + } + + if (sessionHandleLockTaken) + { + Monitor.Exit(SessionHandle); + sessionHandleLockTaken = false; + } + } + } + } + + private void EnsureReceiveOperation() + { + if (_receiveOperation == null) + { + lock (_thisLock) + { + if (_receiveOperation == null) + { + _receiveOperation = new WebSocketOperation.ReceiveOperation(this); + } + } + } + } + + private void EnsureSendOperation() + { + if (_sendOperation == null) + { + lock (_thisLock) + { + if (_sendOperation == null) + { + _sendOperation = new WebSocketOperation.SendOperation(this); + } + } + } + } + + private void EnsureKeepAliveOperation() + { + if (_keepAliveOperation == null) + { + lock (_thisLock) + { + if (_keepAliveOperation == null) + { + WebSocketOperation.SendOperation keepAliveOperation = new WebSocketOperation.SendOperation(this); + keepAliveOperation.BufferType = UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UnsolicitedPong; + _keepAliveOperation = keepAliveOperation; + } + } + } + } + + private void EnsureCloseOutputOperation() + { + if (_closeOutputOperation == null) + { + lock (_thisLock) + { + if (_closeOutputOperation == null) + { + _closeOutputOperation = new WebSocketOperation.CloseOutputOperation(this); + } + } + } + } + + private static void ReleaseLock(object lockObject, ref bool lockTaken) + { + Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); + if (lockTaken) + { +#if NET45 + RuntimeHelpers.PrepareConstrainedRegions(); +#endif + try + { + } + finally + { + Monitor.Exit(lockObject); + lockTaken = false; + } + } + } + + private static UnsafeNativeMethods.WebSocketProtocolComponent.BufferType GetBufferType(WebSocketMessageType messageType, + bool endOfMessage) + { + Contract.Assert(messageType == WebSocketMessageType.Binary || messageType == WebSocketMessageType.Text, + string.Format(CultureInfo.InvariantCulture, + "The value of 'messageType' ({0}) is invalid. Valid message types: '{1}, {2}'", + messageType, + WebSocketMessageType.Binary, + WebSocketMessageType.Text)); + + if (messageType == WebSocketMessageType.Text) + { + if (endOfMessage) + { + return UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message; + } + + return UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment; + } + else + { + if (endOfMessage) + { + return UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage; + } + + return UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment; + } + } + + private static WebSocketMessageType GetMessageType(UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType) + { + switch (bufferType) + { + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close: + return WebSocketMessageType.Close; + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment: + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage: + return WebSocketMessageType.Binary; + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment: + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message: + return WebSocketMessageType.Text; + default: + // This indicates a contract violation of the websocket protocol component, + // because we currently don't support any WebSocket extensions and would + // not accept a Websocket handshake requesting extensions + Contract.Assert(false, + string.Format(CultureInfo.InvariantCulture, + "The value of 'bufferType' ({0}) is invalid. Valid buffer types: {1}, {2}, {3}, {4}, {5}.", + bufferType, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message)); + + throw new WebSocketException(WebSocketError.NativeError, + SR.GetString(SR.net_WebSockets_InvalidBufferType, + bufferType, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message)); + } + } + + internal void ValidateNativeBuffers(UnsafeNativeMethods.WebSocketProtocolComponent.Action action, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers, + uint dataBufferCount) + { + _internalBuffer.ValidateNativeBuffers(action, bufferType, dataBuffers, dataBufferCount); + } + + internal void ThrowIfClosedOrAborted() + { + if (State == WebSocketState.Closed || State == WebSocketState.Aborted) + { + throw new WebSocketException(WebSocketError.InvalidState, + SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, GetType().FullName, State)); + } + } + + private void ThrowIfAborted(bool aborted, Exception innerException) + { + if (aborted) + { + throw new WebSocketException(WebSocketError.InvalidState, + SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, GetType().FullName, WebSocketState.Aborted), + innerException); + } + } + + private bool CanHandleExceptionDuringClose(Exception error) + { + Contract.Assert(error != null, "'error' MUST NOT be NULL."); + + if (State != WebSocketState.Closed) + { + return false; + } + + return error is OperationCanceledException || + error is WebSocketException || + // error is SocketException || + // error is HttpListenerException || + error is IOException; + } + + // We only want to throw an OperationCanceledException if the CancellationToken passed + // down from the caller is canceled - not when Abort is called on another thread and + // the linkedCancellationToken is canceled. + private void ThrowIfConvertibleException(string methodName, + Exception exception, + CancellationToken cancellationToken, + bool aborted) + { + Contract.Assert(exception != null, "'exception' MUST NOT be NULL."); + /* + if (s_LoggingEnabled && !string.IsNullOrEmpty(methodName)) + { + Logging.Exception(Logging.WebSockets, this, methodName, exception); + }*/ + + OperationCanceledException operationCanceledException = exception as OperationCanceledException; + if (operationCanceledException != null) + { + if (cancellationToken.IsCancellationRequested || + !aborted) + { + return; + } + ThrowIfAborted(aborted, exception); + } + + WebSocketException convertedException = exception as WebSocketException; + if (convertedException != null) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfAborted(aborted, convertedException); + return; + } + /* + SocketException socketException = exception as SocketException; + if (socketException != null) + { + convertedException = new WebSocketException(socketException.NativeErrorCode, socketException); + } + HttpListenerException httpListenerException = exception as HttpListenerException; + if (httpListenerException != null) + { + convertedException = new WebSocketException(httpListenerException.ErrorCode, httpListenerException); + } + + IOException ioException = exception as IOException; + if (ioException != null) + { + socketException = exception.InnerException as SocketException; + if (socketException != null) + { + convertedException = new WebSocketException(socketException.NativeErrorCode, ioException); + } + } +*/ + if (convertedException != null) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfAborted(aborted, convertedException); + throw convertedException; + } + + AggregateException aggregateException = exception as AggregateException; + if (aggregateException != null) + { + // Collapse possibly nested graph into a flat list. + // Empty inner exception list is unlikely but possible via public api. + ReadOnlyCollection unwrappedExceptions = aggregateException.Flatten().InnerExceptions; + if (unwrappedExceptions.Count == 0) + { + return; + } + + foreach (Exception unwrappedException in unwrappedExceptions) + { + ThrowIfConvertibleException(null, unwrappedException, cancellationToken, aborted); + } + } + } + + private void CleanUp() + { + // Multithreading: This method is always called under the m_ThisLock lock + if (_cleanedUp) + { + return; + } + + _cleanedUp = true; + + if (SessionHandle != null) + { + SessionHandle.Dispose(); + } + + if (_internalBuffer != null) + { + _internalBuffer.Dispose(this.State); + } + + if (_receiveOutstandingOperationHelper != null) + { + _receiveOutstandingOperationHelper.Dispose(); + } + + if (_sendOutstandingOperationHelper != null) + { + _sendOutstandingOperationHelper.Dispose(); + } + + if (_closeOutputOutstandingOperationHelper != null) + { + _closeOutputOutstandingOperationHelper.Dispose(); + } + + if (_closeOutstandingOperationHelper != null) + { + _closeOutstandingOperationHelper.Dispose(); + } + + if (_innerStream != null) + { + try + { + _innerStream.Dispose(); + } + catch (ObjectDisposedException) + { + } + catch (IOException) + { + } + /*catch (SocketException) + { + }*/ + catch (Exception) + { + } + } + + _keepAliveTracker.Dispose(); + } + + private void OnBackgroundTaskException(Exception exception) + { + if (Interlocked.CompareExchange(ref _pendingException, exception, null) == null) + { + /*if (s_LoggingEnabled) + { + Logging.Exception(Logging.WebSockets, this, Methods.Fault, exception); + }*/ + Abort(); + } + } + + private void ThrowIfPendingException() + { + Exception pendingException = Interlocked.Exchange(ref _pendingException, null); + if (pendingException != null) + { + throw new WebSocketException(WebSocketError.Faulted, pendingException); + } + } + + private void ThrowIfDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(GetType().FullName); + } + } + + private void UpdateReceiveState(int newReceiveState, int expectedReceiveState) + { + int receiveState; + if ((receiveState = Interlocked.Exchange(ref _receiveState, newReceiveState)) != expectedReceiveState) + { + Contract.Assert(false, + string.Format(CultureInfo.InvariantCulture, + "'m_ReceiveState' had an invalid value '{0}'. The expected value was '{1}'.", + receiveState, + expectedReceiveState)); + } + } + + private bool StartOnCloseReceived(ref bool thisLockTaken) + { + ThrowIfDisposed(); + + if (IsStateTerminal(State) || State == WebSocketState.CloseReceived) + { + return false; + } + + Monitor.Enter(_thisLock, ref thisLockTaken); + if (IsStateTerminal(State) || State == WebSocketState.CloseReceived) + { + return false; + } + + if (State == WebSocketState.Open) + { + _state = WebSocketState.CloseReceived; + + if (_closeReceivedTaskCompletionSource == null) + { + _closeReceivedTaskCompletionSource = new TaskCompletionSource(); + } + + return false; + } + + return true; + } + + private void FinishOnCloseReceived(WebSocketCloseStatus closeStatus, + string closeStatusDescription) + { + if (_closeReceivedTaskCompletionSource != null) + { + _closeReceivedTaskCompletionSource.TrySetResult(null); + } + + _closeStatus = closeStatus; + _closeStatusDescription = closeStatusDescription; + /* + if (s_LoggingEnabled) + { + string parameters = string.Format(CultureInfo.InvariantCulture, + "closeStatus: {0}, closeStatusDescription: {1}, m_State: {2}", + closeStatus, closeStatusDescription, m_State); + + Logging.PrintInfo(Logging.WebSockets, this, Methods.FinishOnCloseReceived, parameters); + }*/ + } + + private async static void OnKeepAlive(object sender) + { + Contract.Assert(sender != null, "'sender' MUST NOT be NULL."); + Contract.Assert((sender as WebSocketBase) != null, "'sender as WebSocketBase' MUST NOT be NULL."); + + WebSocketBase thisPtr = sender as WebSocketBase; + bool lockTaken = false; + /* + if (s_LoggingEnabled) + { + Logging.Enter(Logging.WebSockets, thisPtr, Methods.OnKeepAlive, string.Empty); + }*/ + + CancellationToken linkedCancellationToken = CancellationToken.None; + try + { + Monitor.Enter(thisPtr.SessionHandle, ref lockTaken); + + if (thisPtr._isDisposed || + thisPtr._state != WebSocketState.Open || + thisPtr._closeOutputTask != null) + { + return; + } + + if (thisPtr._keepAliveTracker.ShouldSendKeepAlive()) + { + bool ownsCancellationTokenSource = false; + try + { + ownsCancellationTokenSource = thisPtr._sendOutstandingOperationHelper.TryStartOperation(CancellationToken.None, out linkedCancellationToken); + if (ownsCancellationTokenSource) + { + thisPtr.EnsureKeepAliveOperation(); + thisPtr._keepAliveTask = thisPtr._keepAliveOperation.Process(null, linkedCancellationToken); + ReleaseLock(thisPtr.SessionHandle, ref lockTaken); + await thisPtr._keepAliveTask.SuppressContextFlow(); + } + } + finally + { + if (!lockTaken) + { + Monitor.Enter(thisPtr.SessionHandle, ref lockTaken); + } + thisPtr._sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); + thisPtr._keepAliveTask = null; + } + + thisPtr._keepAliveTracker.ResetTimer(); + } + } + catch (Exception exception) + { + try + { + thisPtr.ThrowIfConvertibleException(Methods.OnKeepAlive, + exception, + CancellationToken.None, + linkedCancellationToken.IsCancellationRequested); + throw; + } + catch (Exception backgroundException) + { + thisPtr.OnBackgroundTaskException(backgroundException); + } + } + finally + { + ReleaseLock(thisPtr.SessionHandle, ref lockTaken); + /* + if (s_LoggingEnabled) + { + Logging.Exit(Logging.WebSockets, thisPtr, Methods.OnKeepAlive, string.Empty); + }*/ + } + } + + private abstract class WebSocketOperation + { + private readonly WebSocketBase _webSocket; + + internal WebSocketOperation(WebSocketBase webSocket) + { + Contract.Assert(webSocket != null, "'webSocket' MUST NOT be NULL."); + _webSocket = webSocket; + } + + public WebSocketReceiveResult ReceiveResult { get; protected set; } + protected abstract int BufferCount { get; } + protected abstract UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue ActionQueue { get; } + protected abstract void Initialize(ArraySegment? buffer, CancellationToken cancellationToken); + protected abstract bool ShouldContinue(CancellationToken cancellationToken); + + // Multi-Threading: This method has to be called under a SessionHandle-lock. It returns true if a + // close frame was received. Handling the received close frame might involve IO - to make the locking + // strategy easier and reduce one level in the await-hierarchy the IO is kicked off by the caller. + protected abstract bool ProcessAction_NoAction(); + + protected virtual void ProcessAction_IndicateReceiveComplete( + ArraySegment? buffer, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, + UnsafeNativeMethods.WebSocketProtocolComponent.Action action, + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers, + uint dataBufferCount, + IntPtr actionContext) + { + throw new NotImplementedException(); + } + + protected abstract void Cleanup(); + + internal async Task Process(ArraySegment? buffer, + CancellationToken cancellationToken) + { + Contract.Assert(BufferCount >= 1 && BufferCount <= 2, "'bufferCount' MUST ONLY BE '1' or '2'."); + + bool sessionHandleLockTaken = false; + ReceiveResult = null; + try + { + Monitor.Enter(_webSocket.SessionHandle, ref sessionHandleLockTaken); + _webSocket.ThrowIfPendingException(); + Initialize(buffer, cancellationToken); + + while (ShouldContinue(cancellationToken)) + { + UnsafeNativeMethods.WebSocketProtocolComponent.Action action; + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType; + + bool completed = false; + while (!completed) + { + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers = + new UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[BufferCount]; + uint dataBufferCount = (uint)BufferCount; + IntPtr actionContext; + + _webSocket.ThrowIfDisposed(); + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketGetAction(_webSocket, + ActionQueue, + dataBuffers, + ref dataBufferCount, + out action, + out bufferType, + out actionContext); + + switch (action) + { + case UnsafeNativeMethods.WebSocketProtocolComponent.Action.NoAction: + if (ProcessAction_NoAction()) + { + // A close frame was received + + Contract.Assert(ReceiveResult.Count == 0, "'receiveResult.Count' MUST be 0."); + Contract.Assert(ReceiveResult.CloseStatus != null, "'receiveResult.CloseStatus' MUST NOT be NULL for message type 'Close'."); + bool thisLockTaken = false; + try + { + if (_webSocket.StartOnCloseReceived(ref thisLockTaken)) + { + // If StartOnCloseReceived returns true the WebSocket close handshake has been completed + // so there is no need to retake the SessionHandle-lock. + // m_ThisLock lock is guaranteed to be taken by StartOnCloseReceived when returning true + ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); + bool callCompleteOnCloseCompleted = false; + + try + { + callCompleteOnCloseCompleted = await _webSocket.StartOnCloseCompleted( + thisLockTaken, sessionHandleLockTaken, cancellationToken).SuppressContextFlow(); + } + catch (Exception) + { + // If an exception is thrown we know that the locks have been released, + // because we enforce IWebSocketStream.CloseNetworkConnectionAsync to yield + _webSocket.ResetFlagAndTakeLock(_webSocket._thisLock, ref thisLockTaken); + throw; + } + + if (callCompleteOnCloseCompleted) + { + _webSocket.ResetFlagAndTakeLock(_webSocket._thisLock, ref thisLockTaken); + _webSocket.FinishOnCloseCompleted(); + } + } + _webSocket.FinishOnCloseReceived(ReceiveResult.CloseStatus.Value, ReceiveResult.CloseStatusDescription); + } + finally + { + if (thisLockTaken) + { + ReleaseLock(_webSocket._thisLock, ref thisLockTaken); + } + } + } + completed = true; + break; + case UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateReceiveComplete: + ProcessAction_IndicateReceiveComplete(buffer, + bufferType, + action, + dataBuffers, + dataBufferCount, + actionContext); + break; + case UnsafeNativeMethods.WebSocketProtocolComponent.Action.ReceiveFromNetwork: + int count = 0; + try + { + ArraySegment payload = _webSocket._internalBuffer.ConvertNativeBuffer(action, dataBuffers[0], bufferType); + + ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); + WebSocketHelpers.ThrowIfConnectionAborted(_webSocket._innerStream, true); + try + { + Task readTask = _webSocket._innerStream.ReadAsync(payload.Array, + payload.Offset, + payload.Count, + cancellationToken); + count = await readTask.SuppressContextFlow(); + _webSocket._keepAliveTracker.OnDataReceived(); + } + catch (ObjectDisposedException objectDisposedException) + { + throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, objectDisposedException); + } + catch (NotSupportedException notSupportedException) + { + throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, notSupportedException); + } + Monitor.Enter(_webSocket.SessionHandle, ref sessionHandleLockTaken); + _webSocket.ThrowIfPendingException(); + // If the client unexpectedly closed the socket we throw an exception as we didn't get any close message + if (count == 0) + { + throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely); + } + } + finally + { + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, + actionContext, + count); + } + break; + case UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateSendComplete: + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, actionContext, 0); + ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); + await _webSocket._innerStream.FlushAsync().SuppressContextFlow(); + Monitor.Enter(_webSocket.SessionHandle, ref sessionHandleLockTaken); + break; + case UnsafeNativeMethods.WebSocketProtocolComponent.Action.SendToNetwork: + int bytesSent = 0; + try + { + if (_webSocket.State != WebSocketState.CloseSent || + (bufferType != UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.PingPong && + bufferType != UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UnsolicitedPong)) + { + if (dataBufferCount == 0) + { + break; + } + + List> sendBuffers = new List>((int)dataBufferCount); + int sendBufferSize = 0; + ArraySegment framingBuffer = _webSocket._internalBuffer.ConvertNativeBuffer(action, dataBuffers[0], bufferType); + sendBuffers.Add(framingBuffer); + sendBufferSize += framingBuffer.Count; + + // There can be at most 2 dataBuffers + // - one for the framing header and one for the payload + if (dataBufferCount == 2) + { + ArraySegment payload = _webSocket._internalBuffer.ConvertPinnedSendPayloadFromNative(dataBuffers[1], bufferType); + sendBuffers.Add(payload); + sendBufferSize += payload.Count; + } + + ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); + WebSocketHelpers.ThrowIfConnectionAborted(_webSocket._innerStream, false); + await _webSocket.SendFrameAsync(sendBuffers, cancellationToken).SuppressContextFlow(); + Monitor.Enter(_webSocket.SessionHandle, ref sessionHandleLockTaken); + _webSocket.ThrowIfPendingException(); + bytesSent += sendBufferSize; + _webSocket._keepAliveTracker.OnDataSent(); + } + } + finally + { + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, + actionContext, + bytesSent); + } + + break; + default: + string assertMessage = string.Format(CultureInfo.InvariantCulture, + "Invalid action '{0}' returned from WebSocketGetAction.", + action); + Contract.Assert(false, assertMessage); + throw new InvalidOperationException(); + } + } + } + } + finally + { + Cleanup(); + ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); + } + + return ReceiveResult; + } + + public class ReceiveOperation : WebSocketOperation + { + private int _receiveState; + private bool _pongReceived; + private bool _receiveCompleted; + + public ReceiveOperation(WebSocketBase webSocket) + : base(webSocket) + { + } + + protected override UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue ActionQueue + { + get { return UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue.Receive; } + } + + protected override int BufferCount + { + get { return 1; } + } + + protected override void Initialize(ArraySegment? buffer, CancellationToken cancellationToken) + { + Contract.Assert(buffer != null, "'buffer' MUST NOT be NULL."); + _pongReceived = false; + _receiveCompleted = false; + _webSocket.ThrowIfDisposed(); + + int originalReceiveState = Interlocked.CompareExchange(ref _webSocket._receiveState, + ReceiveState.Application, ReceiveState.Idle); + + switch (originalReceiveState) + { + case ReceiveState.Idle: + _receiveState = ReceiveState.Application; + break; + case ReceiveState.Application: + Contract.Assert(false, "'originalReceiveState' MUST NEVER be ReceiveState.Application at this point."); + break; + case ReceiveState.PayloadAvailable: + WebSocketReceiveResult receiveResult; + if (!_webSocket._internalBuffer.ReceiveFromBufferedPayload(buffer.Value, out receiveResult)) + { + _webSocket.UpdateReceiveState(ReceiveState.Idle, ReceiveState.PayloadAvailable); + } + ReceiveResult = receiveResult; + _receiveCompleted = true; + break; + default: + Contract.Assert(false, + string.Format(CultureInfo.InvariantCulture, "Invalid ReceiveState '{0}'.", originalReceiveState)); + break; + } + } + + protected override void Cleanup() + { + } + + protected override bool ShouldContinue(CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (_receiveCompleted) + { + return false; + } + + _webSocket.ThrowIfDisposed(); + _webSocket.ThrowIfPendingException(); + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketReceive(_webSocket); + + return true; + } + + protected override bool ProcessAction_NoAction() + { + if (_pongReceived) + { + _receiveCompleted = false; + _pongReceived = false; + return false; + } + + Contract.Assert(ReceiveResult != null, + "'ReceiveResult' MUST NOT be NULL."); + _receiveCompleted = true; + + if (ReceiveResult.MessageType == WebSocketMessageType.Close) + { + return true; + } + + return false; + } + + protected override void ProcessAction_IndicateReceiveComplete( + ArraySegment? buffer, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, + UnsafeNativeMethods.WebSocketProtocolComponent.Action action, + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers, + uint dataBufferCount, + IntPtr actionContext) + { + Contract.Assert(buffer != null, "'buffer MUST NOT be NULL."); + + int bytesTransferred = 0; + _pongReceived = false; + + if (bufferType == UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.PingPong) + { + // ignoring received pong frame + _pongReceived = true; + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, + actionContext, + bytesTransferred); + return; + } + + WebSocketReceiveResult receiveResult; + try + { + ArraySegment payload; + WebSocketMessageType messageType = GetMessageType(bufferType); + int newReceiveState = ReceiveState.Idle; + + if (bufferType == UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close) + { + payload = WebSocketHelpers.EmptyPayload; + string reason; + WebSocketCloseStatus closeStatus; + _webSocket._internalBuffer.ConvertCloseBuffer(action, dataBuffers[0], out closeStatus, out reason); + + receiveResult = new WebSocketReceiveResult(bytesTransferred, + messageType, true, closeStatus, reason); + } + else + { + payload = _webSocket._internalBuffer.ConvertNativeBuffer(action, dataBuffers[0], bufferType); + + bool endOfMessage = bufferType == + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage || + bufferType == UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message || + bufferType == UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close; + + if (payload.Count > buffer.Value.Count) + { + _webSocket._internalBuffer.BufferPayload(payload, buffer.Value.Count, messageType, endOfMessage); + newReceiveState = ReceiveState.PayloadAvailable; + endOfMessage = false; + } + + bytesTransferred = Math.Min(payload.Count, (int)buffer.Value.Count); + if (bytesTransferred > 0) + { + Buffer.BlockCopy(payload.Array, + payload.Offset, + buffer.Value.Array, + buffer.Value.Offset, + bytesTransferred); + } + + receiveResult = new WebSocketReceiveResult(bytesTransferred, messageType, endOfMessage); + } + + _webSocket.UpdateReceiveState(newReceiveState, _receiveState); + } + finally + { + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, + actionContext, + bytesTransferred); + } + + ReceiveResult = receiveResult; + } + } + + public class SendOperation : WebSocketOperation + { + private bool _completed; + protected bool _bufferHasBeenPinned; + + public SendOperation(WebSocketBase webSocket) + : base(webSocket) + { + } + + protected override UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue ActionQueue + { + get { return UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue.Send; } + } + + protected override int BufferCount + { + get { return 2; } + } + + protected virtual UnsafeNativeMethods.WebSocketProtocolComponent.Buffer? CreateBuffer(ArraySegment? buffer) + { + if (buffer == null) + { + return null; + } + + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer payloadBuffer; + payloadBuffer = new UnsafeNativeMethods.WebSocketProtocolComponent.Buffer(); + _webSocket._internalBuffer.PinSendBuffer(buffer.Value, out _bufferHasBeenPinned); + payloadBuffer.Data.BufferData = _webSocket._internalBuffer.ConvertPinnedSendPayloadToNative(buffer.Value); + payloadBuffer.Data.BufferLength = (uint)buffer.Value.Count; + return payloadBuffer; + } + + protected override bool ProcessAction_NoAction() + { + _completed = true; + return false; + } + + protected override void Cleanup() + { + if (_bufferHasBeenPinned) + { + _bufferHasBeenPinned = false; + _webSocket._internalBuffer.ReleasePinnedSendBuffer(); + } + } + + internal UnsafeNativeMethods.WebSocketProtocolComponent.BufferType BufferType { get; set; } + + protected override void Initialize(ArraySegment? buffer, + CancellationToken cancellationToken) + { + Contract.Assert(!_bufferHasBeenPinned, "'m_BufferHasBeenPinned' MUST NOT be pinned at this point."); + _webSocket.ThrowIfDisposed(); + _webSocket.ThrowIfPendingException(); + _completed = false; + + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer? payloadBuffer = CreateBuffer(buffer); + if (payloadBuffer != null) + { + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketSend(_webSocket, BufferType, payloadBuffer.Value); + } + else + { + UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketSendWithoutBody(_webSocket, BufferType); + } + } + + protected override bool ShouldContinue(CancellationToken cancellationToken) + { + Contract.Assert(ReceiveResult == null, "'ReceiveResult' MUST be NULL."); + if (_completed) + { + return false; + } + + cancellationToken.ThrowIfCancellationRequested(); + return true; + } + } + + public class CloseOutputOperation : SendOperation + { + public CloseOutputOperation(WebSocketBase webSocket) + : base(webSocket) + { + BufferType = UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close; + } + + internal WebSocketCloseStatus CloseStatus { get; set; } + internal string CloseReason { get; set; } + + protected override UnsafeNativeMethods.WebSocketProtocolComponent.Buffer? CreateBuffer(ArraySegment? buffer) + { + Contract.Assert(buffer == null, "'buffer' MUST BE NULL."); + _webSocket.ThrowIfDisposed(); + _webSocket.ThrowIfPendingException(); + + if (CloseStatus == WebSocketCloseStatus.Empty) + { + return null; + } + + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer payloadBuffer = new UnsafeNativeMethods.WebSocketProtocolComponent.Buffer(); + if (CloseReason != null) + { + byte[] blob = UTF8Encoding.UTF8.GetBytes(CloseReason); + Contract.Assert(blob.Length <= WebSocketHelpers.MaxControlFramePayloadLength, + "The close reason is too long."); + ArraySegment closeBuffer = new ArraySegment(blob, 0, Math.Min(WebSocketHelpers.MaxControlFramePayloadLength, blob.Length)); + _webSocket._internalBuffer.PinSendBuffer(closeBuffer, out _bufferHasBeenPinned); + payloadBuffer.CloseStatus.ReasonData = _webSocket._internalBuffer.ConvertPinnedSendPayloadToNative(closeBuffer); + payloadBuffer.CloseStatus.ReasonLength = (uint)closeBuffer.Count; + } + + payloadBuffer.CloseStatus.CloseStatus = (ushort)CloseStatus; + return payloadBuffer; + } + } + } + + private abstract class KeepAliveTracker : IDisposable + { + // Multi-Threading: only one thread at a time is allowed to call OnDataReceived or OnDataSent + // - but both methods can be called from different threads at the same time. + public abstract void OnDataReceived(); + public abstract void OnDataSent(); + public abstract void Dispose(); + public abstract void StartTimer(WebSocketBase webSocket); + public abstract void ResetTimer(); + public abstract bool ShouldSendKeepAlive(); + + public static KeepAliveTracker Create(TimeSpan keepAliveInterval) + { + if ((int)keepAliveInterval.TotalMilliseconds > 0) + { + return new DefaultKeepAliveTracker(keepAliveInterval); + } + + return new DisabledKeepAliveTracker(); + } + + private class DisabledKeepAliveTracker : KeepAliveTracker + { + public override void OnDataReceived() + { + } + + public override void OnDataSent() + { + } + + public override void ResetTimer() + { + } + + public override void StartTimer(WebSocketBase webSocket) + { + } + + public override bool ShouldSendKeepAlive() + { + return false; + } + + public override void Dispose() + { + } + } + + private class DefaultKeepAliveTracker : KeepAliveTracker + { + private static readonly TimerCallback _keepAliveTimerElapsedCallback = new TimerCallback(OnKeepAlive); + private readonly TimeSpan _keepAliveInterval; + private readonly Stopwatch _lastSendActivity; + private readonly Stopwatch _lastReceiveActivity; + private Timer _keepAliveTimer; + + public DefaultKeepAliveTracker(TimeSpan keepAliveInterval) + { + _keepAliveInterval = keepAliveInterval; + _lastSendActivity = new Stopwatch(); + _lastReceiveActivity = new Stopwatch(); + } + + public override void OnDataReceived() + { + _lastReceiveActivity.Restart(); + } + + public override void OnDataSent() + { + _lastSendActivity.Restart(); + } + + public override void ResetTimer() + { + ResetTimer((int)_keepAliveInterval.TotalMilliseconds); + } + + public override void StartTimer(WebSocketBase webSocket) + { + Contract.Assert(webSocket != null, "'webSocket' MUST NOT be NULL."); + Contract.Assert(webSocket._keepAliveTracker != null, + "'webSocket.m_KeepAliveTracker' MUST NOT be NULL at this point."); + int keepAliveIntervalMilliseconds = (int)_keepAliveInterval.TotalMilliseconds; + Contract.Assert(keepAliveIntervalMilliseconds > 0, "'keepAliveIntervalMilliseconds' MUST be POSITIVE."); +#if NET45 + if (ExecutionContext.IsFlowSuppressed()) + { + _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); + } + else + { + using (ExecutionContext.SuppressFlow()) + { + _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); + } + } +#else + _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); +#endif + } + + public override bool ShouldSendKeepAlive() + { + TimeSpan idleTime = GetIdleTime(); + if (idleTime >= _keepAliveInterval) + { + return true; + } + + ResetTimer((int)(_keepAliveInterval - idleTime).TotalMilliseconds); + return false; + } + + public override void Dispose() + { + _keepAliveTimer.Dispose(); + } + + private void ResetTimer(int dueInMilliseconds) + { + _keepAliveTimer.Change(dueInMilliseconds, Timeout.Infinite); + } + + private TimeSpan GetIdleTime() + { + TimeSpan sinceLastSendActivity = GetTimeElapsed(_lastSendActivity); + TimeSpan sinceLastReceiveActivity = GetTimeElapsed(_lastReceiveActivity); + + if (sinceLastReceiveActivity < sinceLastSendActivity) + { + return sinceLastReceiveActivity; + } + + return sinceLastSendActivity; + } + + private TimeSpan GetTimeElapsed(Stopwatch watch) + { + if (watch.IsRunning) + { + return watch.Elapsed; + } + + return _keepAliveInterval; + } + } + } + + private class OutstandingOperationHelper : IDisposable + { + private volatile int _operationsOutstanding; + private volatile CancellationTokenSource _cancellationTokenSource; + private volatile bool _isDisposed; + private readonly object _thisLock = new object(); + + public bool TryStartOperation(CancellationToken userCancellationToken, out CancellationToken linkedCancellationToken) + { + linkedCancellationToken = CancellationToken.None; + ThrowIfDisposed(); + + lock (_thisLock) + { + int operationsOutstanding = ++_operationsOutstanding; + + if (operationsOutstanding == 1) + { + linkedCancellationToken = CreateLinkedCancellationToken(userCancellationToken); + return true; + } + + Contract.Assert(operationsOutstanding >= 1, "'operationsOutstanding' must never be smaller than 1."); + return false; + } + } + + public void CompleteOperation(bool ownsCancellationTokenSource) + { + if (_isDisposed) + { + // no-op if the WebSocket is already aborted + return; + } + + CancellationTokenSource snapshot = null; + + lock (_thisLock) + { + --_operationsOutstanding; + Contract.Assert(_operationsOutstanding >= 0, "'m_OperationsOutstanding' must never be smaller than 0."); + + if (ownsCancellationTokenSource) + { + snapshot = _cancellationTokenSource; + _cancellationTokenSource = null; + } + } + + if (snapshot != null) + { + snapshot.Dispose(); + } + } + + // Has to be called under m_ThisLock lock + private CancellationToken CreateLinkedCancellationToken(CancellationToken cancellationToken) + { + CancellationTokenSource linkedCancellationTokenSource; + + if (cancellationToken == CancellationToken.None) + { + linkedCancellationTokenSource = new CancellationTokenSource(); + } + else + { + linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, + new CancellationTokenSource().Token); + } + + Contract.Assert(_cancellationTokenSource == null, "'m_CancellationTokenSource' MUST be NULL."); + _cancellationTokenSource = linkedCancellationTokenSource; + + return linkedCancellationTokenSource.Token; + } + + public void CancelIO() + { + CancellationTokenSource cancellationTokenSourceSnapshot = null; + + lock (_thisLock) + { + if (_operationsOutstanding == 0) + { + return; + } + + cancellationTokenSourceSnapshot = _cancellationTokenSource; + } + + if (cancellationTokenSourceSnapshot != null) + { + try + { + cancellationTokenSourceSnapshot.Cancel(); + } + catch (ObjectDisposedException) + { + // Simply ignore this exception - There is apparently a rare race condition + // where the cancellationTokensource is disposed before the Cancel method call completed. + } + } + } + + public void Dispose() + { + if (_isDisposed) + { + return; + } + + CancellationTokenSource snapshot = null; + lock (_thisLock) + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + snapshot = _cancellationTokenSource; + _cancellationTokenSource = null; + } + + if (snapshot != null) + { + snapshot.Dispose(); + } + } + + private void ThrowIfDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(GetType().FullName); + } + } + } + + internal interface IWebSocketStream + { + // Switching to opaque mode will change the behavior to use the knowledge that the WebSocketBase class + // is pinning all payloads already and that we will have at most one outstanding send and receive at any + // given time. This allows us to avoid creation of OverlappedData and pinning for each operation. + + void SwitchToOpaqueMode(WebSocketBase webSocket); + void Abort(); + bool SupportsMultipleWrite { get; } + Task MultipleWriteAsync(IList> buffers, CancellationToken cancellationToken); + + // Any implementation has to guarantee that no exception is thrown synchronously + // for example by enforcing a Task.Yield at the beginning of the method + // This is necessary to enforce an API contract (for WebSocketBase.StartOnCloseCompleted) that ensures + // that all locks have been released whenever an exception is thrown from it. + Task CloseNetworkConnectionAsync(CancellationToken cancellationToken); + } + + private static class ReceiveState + { + internal const int SendOperation = -1; + internal const int Idle = 0; + internal const int Application = 1; + internal const int PayloadAvailable = 2; + } + + internal static class Methods + { + internal const string ReceiveAsync = "ReceiveAsync"; + internal const string SendAsync = "SendAsync"; + internal const string CloseAsync = "CloseAsync"; + internal const string CloseOutputAsync = "CloseOutputAsync"; + internal const string Abort = "Abort"; + internal const string Initialize = "Initialize"; + internal const string Fault = "Fault"; + internal const string StartOnCloseCompleted = "StartOnCloseCompleted"; + internal const string FinishOnCloseReceived = "FinishOnCloseReceived"; + internal const string OnKeepAlive = "OnKeepAlive"; + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs b/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs new file mode 100644 index 0000000000..56b24a4fed --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs @@ -0,0 +1,698 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace Microsoft.AspNet.WebSockets +{ + // This class helps to abstract the internal WebSocket buffer, which is used to interact with the native WebSocket + // protocol component (WSPC). It helps to shield the details of the layout and the involved pointer arithmetic. + // The internal WebSocket buffer also contains a segment, which is used by the WebSocketBase class to buffer + // payload (parsed by WSPC already) for the application, if the application requested fewer bytes than the + // WSPC returned. The internal buffer is pinned for the whole lifetime if this class. + // LAYOUT: + // | Native buffer | PayloadReceiveBuffer | PropertyBuffer | + // | RBS + SBS + 144 | RBS | PBS | + // | Only WSPC may modify | Only WebSocketBase may modify | + // + // *RBS = ReceiveBufferSize, *SBS = SendBufferSize + // *PBS = PropertyBufferSize (32-bit: 16, 64 bit: 20 bytes) + internal class WebSocketBuffer : IDisposable + { + private const int NativeOverheadBufferSize = 144; + internal const int MinSendBufferSize = 16; + internal const int MinReceiveBufferSize = 256; + internal const int MaxBufferSize = 64 * 1024; +#if NET45 + private static readonly int SizeOfUInt = Marshal.SizeOf(typeof(uint)); + private static readonly int SizeOfBool = Marshal.SizeOf(typeof(bool)); +#else + private static readonly int SizeOfUInt = Marshal.SizeOf(); + private static readonly int SizeOfBool = Marshal.SizeOf(); +#endif + private static readonly int PropertyBufferSize = (2 * SizeOfUInt) + SizeOfBool + IntPtr.Size; + + private readonly int _ReceiveBufferSize; + + // Indicates the range of the pinned byte[] that can be used by the WSPC (nativeBuffer + pinnedSendBuffer) + private readonly long _StartAddress; + private readonly long _EndAddress; + private readonly GCHandle _GCHandle; + private readonly ArraySegment _InternalBuffer; + private readonly ArraySegment _NativeBuffer; + private readonly ArraySegment _PayloadBuffer; + private readonly ArraySegment _PropertyBuffer; + private readonly int _SendBufferSize; + private volatile int _PayloadOffset; + private volatile WebSocketReceiveResult _BufferedPayloadReceiveResult; + private long _PinnedSendBufferStartAddress; + private long _PinnedSendBufferEndAddress; + private ArraySegment _PinnedSendBuffer; + private GCHandle _PinnedSendBufferHandle; + private int _StateWhenDisposing = int.MinValue; + private int _SendBufferState; + + private WebSocketBuffer(ArraySegment internalBuffer, int receiveBufferSize, int sendBufferSize) + { + Contract.Assert(internalBuffer.Array != null, "'internalBuffer' MUST NOT be NULL."); + Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, + "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + Contract.Assert(sendBufferSize >= MinSendBufferSize, + "'sendBufferSize' MUST be at least " + MinSendBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + Contract.Assert(receiveBufferSize <= MaxBufferSize, + "'receiveBufferSize' MUST NOT exceed " + MaxBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + Contract.Assert(sendBufferSize <= MaxBufferSize, + "'sendBufferSize' MUST NOT exceed " + MaxBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + + _ReceiveBufferSize = receiveBufferSize; + _SendBufferSize = sendBufferSize; + _InternalBuffer = internalBuffer; + _GCHandle = GCHandle.Alloc(internalBuffer.Array, GCHandleType.Pinned); + // Size of the internal buffer owned exclusively by the WSPC. + int nativeBufferSize = _ReceiveBufferSize + _SendBufferSize + NativeOverheadBufferSize; + _StartAddress = Marshal.UnsafeAddrOfPinnedArrayElement(internalBuffer.Array, internalBuffer.Offset).ToInt64(); + _EndAddress = _StartAddress + nativeBufferSize; + _NativeBuffer = new ArraySegment(internalBuffer.Array, internalBuffer.Offset, nativeBufferSize); + _PayloadBuffer = new ArraySegment(internalBuffer.Array, + _NativeBuffer.Offset + _NativeBuffer.Count, + _ReceiveBufferSize); + _PropertyBuffer = new ArraySegment(internalBuffer.Array, + _PayloadBuffer.Offset + _PayloadBuffer.Count, + PropertyBufferSize); + _SendBufferState = SendBufferState.None; + } + + public int ReceiveBufferSize + { + get { return _ReceiveBufferSize; } + } + + public int SendBufferSize + { + get { return _SendBufferSize; } + } + + internal static WebSocketBuffer CreateClientBuffer(ArraySegment internalBuffer, int receiveBufferSize, int sendBufferSize) + { + Contract.Assert(internalBuffer.Count >= GetInternalBufferSize(receiveBufferSize, sendBufferSize, false), + "Array 'internalBuffer' is TOO SMALL. Call Validate before instantiating WebSocketBuffer."); + + return new WebSocketBuffer(internalBuffer, receiveBufferSize, GetNativeSendBufferSize(sendBufferSize, false)); + } + + internal static WebSocketBuffer CreateServerBuffer(ArraySegment internalBuffer, int receiveBufferSize) + { + int sendBufferSize = GetNativeSendBufferSize(MinSendBufferSize, true); + Contract.Assert(internalBuffer.Count >= GetInternalBufferSize(receiveBufferSize, sendBufferSize, true), + "Array 'internalBuffer' is TOO SMALL. Call Validate before instantiating WebSocketBuffer."); + + return new WebSocketBuffer(internalBuffer, receiveBufferSize, sendBufferSize); + } + + public void Dispose(WebSocketState webSocketState) + { + if (Interlocked.CompareExchange(ref _StateWhenDisposing, (int)webSocketState, int.MinValue) != int.MinValue) + { + return; + } + + this.CleanUp(); + } + + public void Dispose() + { + this.Dispose(WebSocketState.None); + } + + internal UnsafeNativeMethods.WebSocketProtocolComponent.Property[] CreateProperties(bool useZeroMaskingKey) + { + ThrowIfDisposed(); + // serialize marshaled property values in the property segment of the internal buffer + IntPtr internalBufferPtr = _GCHandle.AddrOfPinnedObject(); + int offset = _PropertyBuffer.Offset; + Marshal.WriteInt32(internalBufferPtr, offset, _ReceiveBufferSize); + offset += SizeOfUInt; + Marshal.WriteInt32(internalBufferPtr, offset, _SendBufferSize); + offset += SizeOfUInt; + Marshal.WriteIntPtr(internalBufferPtr, offset, internalBufferPtr); + offset += IntPtr.Size; + Marshal.WriteInt32(internalBufferPtr, offset, useZeroMaskingKey ? (int)1 : (int)0); + + int propertyCount = useZeroMaskingKey ? 4 : 3; + UnsafeNativeMethods.WebSocketProtocolComponent.Property[] properties = + new UnsafeNativeMethods.WebSocketProtocolComponent.Property[propertyCount]; + + // Calculate the pointers to the positions of the properties within the internal buffer + offset = _PropertyBuffer.Offset; + properties[0] = new UnsafeNativeMethods.WebSocketProtocolComponent.Property() + { + Type = UnsafeNativeMethods.WebSocketProtocolComponent.PropertyType.ReceiveBufferSize, + PropertySize = (uint)SizeOfUInt, + PropertyData = IntPtr.Add(internalBufferPtr, offset) + }; + offset += SizeOfUInt; + + properties[1] = new UnsafeNativeMethods.WebSocketProtocolComponent.Property() + { + Type = UnsafeNativeMethods.WebSocketProtocolComponent.PropertyType.SendBufferSize, + PropertySize = (uint)SizeOfUInt, + PropertyData = IntPtr.Add(internalBufferPtr, offset) + }; + offset += SizeOfUInt; + + properties[2] = new UnsafeNativeMethods.WebSocketProtocolComponent.Property() + { + Type = UnsafeNativeMethods.WebSocketProtocolComponent.PropertyType.AllocatedBuffer, + PropertySize = (uint)_NativeBuffer.Count, + PropertyData = IntPtr.Add(internalBufferPtr, offset) + }; + offset += IntPtr.Size; + + if (useZeroMaskingKey) + { + properties[3] = new UnsafeNativeMethods.WebSocketProtocolComponent.Property() + { + Type = UnsafeNativeMethods.WebSocketProtocolComponent.PropertyType.DisableMasking, + PropertySize = (uint)SizeOfBool, + PropertyData = IntPtr.Add(internalBufferPtr, offset) + }; + } + + return properties; + } + + // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation + internal void PinSendBuffer(ArraySegment payload, out bool bufferHasBeenPinned) + { + bufferHasBeenPinned = false; + WebSocketHelpers.ValidateBuffer(payload.Array, payload.Offset, payload.Count); + int previousState = Interlocked.Exchange(ref _SendBufferState, SendBufferState.SendPayloadSpecified); + + if (previousState != SendBufferState.None) + { + Contract.Assert(false, "'m_SendBufferState' MUST BE 'None' at this point."); + // Indicates a violation in the API contract that could indicate + // memory corruption because the pinned sendbuffer is shared between managed and native code + throw new AccessViolationException(); + } + _PinnedSendBuffer = payload; + _PinnedSendBufferHandle = GCHandle.Alloc(_PinnedSendBuffer.Array, GCHandleType.Pinned); + bufferHasBeenPinned = true; + _PinnedSendBufferStartAddress = + Marshal.UnsafeAddrOfPinnedArrayElement(_PinnedSendBuffer.Array, _PinnedSendBuffer.Offset).ToInt64(); + _PinnedSendBufferEndAddress = _PinnedSendBufferStartAddress + _PinnedSendBuffer.Count; + } + + // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation + internal IntPtr ConvertPinnedSendPayloadToNative(ArraySegment payload) + { + return ConvertPinnedSendPayloadToNative(payload.Array, payload.Offset, payload.Count); + } + + // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation + internal IntPtr ConvertPinnedSendPayloadToNative(byte[] buffer, int offset, int count) + { + if (!IsPinnedSendPayloadBuffer(buffer, offset, count)) + { + // Indicates a violation in the API contract that could indicate + // memory corruption because the pinned sendbuffer is shared between managed and native code + throw new AccessViolationException(); + } + + Contract.Assert(Marshal.UnsafeAddrOfPinnedArrayElement(_PinnedSendBuffer.Array, + _PinnedSendBuffer.Offset).ToInt64() == _PinnedSendBufferStartAddress, + "'m_PinnedSendBuffer.Array' MUST be pinned during the entire send operation."); + + return new IntPtr(_PinnedSendBufferStartAddress + offset - _PinnedSendBuffer.Offset); + } + + // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation + internal ArraySegment ConvertPinnedSendPayloadFromNative(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType) + { + if (!IsPinnedSendPayloadBuffer(buffer, bufferType)) + { + // Indicates a violation in the API contract that could indicate + // memory corruption because the pinned sendbuffer is shared between managed and native code + throw new AccessViolationException(); + } + + Contract.Assert(Marshal.UnsafeAddrOfPinnedArrayElement(_PinnedSendBuffer.Array, + _PinnedSendBuffer.Offset).ToInt64() == _PinnedSendBufferStartAddress, + "'m_PinnedSendBuffer.Array' MUST be pinned during the entire send operation."); + + IntPtr bufferData; + uint bufferSize; + + UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferSize); + + int internalOffset = (int)(bufferData.ToInt64() - _PinnedSendBufferStartAddress); + + return new ArraySegment(_PinnedSendBuffer.Array, _PinnedSendBuffer.Offset + internalOffset, (int)bufferSize); + } + + // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation + private bool IsPinnedSendPayloadBuffer(byte[] buffer, int offset, int count) + { + if (_SendBufferState != SendBufferState.SendPayloadSpecified) + { + return false; + } + + return object.ReferenceEquals(buffer, _PinnedSendBuffer.Array) && + offset >= _PinnedSendBuffer.Offset && + offset + count <= _PinnedSendBuffer.Offset + _PinnedSendBuffer.Count; + } + + // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation + private bool IsPinnedSendPayloadBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType) + { + if (_SendBufferState != SendBufferState.SendPayloadSpecified) + { + return false; + } + + IntPtr bufferData; + uint bufferSize; + + UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferSize); + + long nativeBufferStartAddress = bufferData.ToInt64(); + long nativeBufferEndAddress = nativeBufferStartAddress + bufferSize; + + return nativeBufferStartAddress >= _PinnedSendBufferStartAddress && + nativeBufferEndAddress >= _PinnedSendBufferStartAddress && + nativeBufferStartAddress <= _PinnedSendBufferEndAddress && + nativeBufferEndAddress <= _PinnedSendBufferEndAddress; + } + + // This method is only thread safe for races between Abort and at most 1 uncompleted send operation + internal void ReleasePinnedSendBuffer() + { + int previousState = Interlocked.Exchange(ref _SendBufferState, SendBufferState.None); + + if (previousState != SendBufferState.SendPayloadSpecified) + { + return; + } + + if (_PinnedSendBufferHandle.IsAllocated) + { + _PinnedSendBufferHandle.Free(); + } + + _PinnedSendBuffer = WebSocketHelpers.EmptyPayload; + } + + internal void BufferPayload(ArraySegment payload, + int unconsumedDataOffset, + WebSocketMessageType messageType, + bool endOfMessage) + { + ThrowIfDisposed(); + int bytesBuffered = payload.Count - unconsumedDataOffset; + + Contract.Assert(_PayloadOffset == 0, + "'m_PayloadOffset' MUST be '0' at this point."); + Contract.Assert(_BufferedPayloadReceiveResult == null || _BufferedPayloadReceiveResult.Count == 0, + "'m_BufferedPayloadReceiveResult.Count' MUST be '0' at this point."); + + Buffer.BlockCopy(payload.Array, + payload.Offset + unconsumedDataOffset, + _PayloadBuffer.Array, + _PayloadBuffer.Offset, + bytesBuffered); + + _BufferedPayloadReceiveResult = + new WebSocketReceiveResult(bytesBuffered, messageType, endOfMessage); + + this.ValidateBufferedPayload(); + } + + internal bool ReceiveFromBufferedPayload(ArraySegment buffer, out WebSocketReceiveResult receiveResult) + { + ThrowIfDisposed(); + ValidateBufferedPayload(); + + int bytesTransferred = Math.Min(buffer.Count, _BufferedPayloadReceiveResult.Count); + receiveResult = _BufferedPayloadReceiveResult.Copy(bytesTransferred); + + Buffer.BlockCopy(_PayloadBuffer.Array, + _PayloadBuffer.Offset + _PayloadOffset, + buffer.Array, + buffer.Offset, + bytesTransferred); + + bool morePayloadBuffered; + if (_BufferedPayloadReceiveResult.Count == 0) + { + _PayloadOffset = 0; + _BufferedPayloadReceiveResult = null; + morePayloadBuffered = false; + } + else + { + _PayloadOffset += bytesTransferred; + morePayloadBuffered = true; + this.ValidateBufferedPayload(); + } + + return morePayloadBuffered; + } + + internal ArraySegment ConvertNativeBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Action action, + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType) + { + ThrowIfDisposed(); + + IntPtr bufferData; + uint bufferLength; + + UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferLength); + + if (bufferData == IntPtr.Zero) + { + return WebSocketHelpers.EmptyPayload; + } + + if (this.IsNativeBuffer(bufferData, bufferLength)) + { + return new ArraySegment(_InternalBuffer.Array, + this.GetOffset(bufferData), + (int)bufferLength); + } + + Contract.Assert(false, "'buffer' MUST reference a memory segment within the pinned InternalBuffer."); + // Indicates a violation in the contract with native Websocket.dll and could indicate + // memory corruption because the internal buffer is shared between managed and native code + throw new AccessViolationException(); + } + + internal void ConvertCloseBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Action action, + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, + out WebSocketCloseStatus closeStatus, + out string reason) + { + ThrowIfDisposed(); + IntPtr bufferData; + uint bufferLength; + closeStatus = (WebSocketCloseStatus)buffer.CloseStatus.CloseStatus; + + UnwrapWebSocketBuffer(buffer, UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close, out bufferData, out bufferLength); + + if (bufferData == IntPtr.Zero) + { + reason = null; + } + else + { + ArraySegment reasonBlob; + if (this.IsNativeBuffer(bufferData, bufferLength)) + { + reasonBlob = new ArraySegment(_InternalBuffer.Array, + this.GetOffset(bufferData), + (int)bufferLength); + } + else + { + Contract.Assert(false, "'buffer' MUST reference a memory segment within the pinned InternalBuffer."); + // Indicates a violation in the contract with native Websocket.dll and could indicate + // memory corruption because the internal buffer is shared between managed and native code + throw new AccessViolationException(); + } + + // No need to wrap DecoderFallbackException for invalid UTF8 chacters, because + // Encoding.UTF8 will not throw but replace invalid characters instead. + reason = Encoding.UTF8.GetString(reasonBlob.Array, reasonBlob.Offset, reasonBlob.Count); + } + } + + internal void ValidateNativeBuffers(UnsafeNativeMethods.WebSocketProtocolComponent.Action action, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers, + uint dataBufferCount) + { + Contract.Assert(dataBufferCount <= (uint)int.MaxValue, + "'dataBufferCount' MUST NOT be bigger than Int32.MaxValue."); + Contract.Assert(dataBuffers != null, "'dataBuffers' MUST NOT be NULL."); + + ThrowIfDisposed(); + if (dataBufferCount > dataBuffers.Length) + { + Contract.Assert(false, "'dataBufferCount' MUST NOT be bigger than 'dataBuffers.Length'."); + // Indicates a violation in the contract with native Websocket.dll and could indicate + // memory corruption because the internal buffer is shared between managed and native code + throw new AccessViolationException(); + } + + int count = dataBuffers.Length; + bool isSendActivity = action == UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateSendComplete || + action == UnsafeNativeMethods.WebSocketProtocolComponent.Action.SendToNetwork; + + if (isSendActivity) + { + count = (int)dataBufferCount; + } + + bool nonZeroBufferFound = false; + for (int i = 0; i < count; i++) + { + UnsafeNativeMethods.WebSocketProtocolComponent.Buffer dataBuffer = dataBuffers[i]; + + IntPtr bufferData; + uint bufferLength; + UnwrapWebSocketBuffer(dataBuffer, bufferType, out bufferData, out bufferLength); + + if (bufferData == IntPtr.Zero) + { + continue; + } + + nonZeroBufferFound = true; + + bool isPinnedSendPayloadBuffer = IsPinnedSendPayloadBuffer(dataBuffer, bufferType); + + if (bufferLength > GetMaxBufferSize()) + { + if (!isSendActivity || !isPinnedSendPayloadBuffer) + { + Contract.Assert(false, + "'dataBuffer.BufferLength' MUST NOT be bigger than 'm_ReceiveBufferSize' and 'm_SendBufferSize'."); + // Indicates a violation in the contract with native Websocket.dll and could indicate + // memory corruption because the internal buffer is shared between managed and native code + throw new AccessViolationException(); + } + } + + if (!isPinnedSendPayloadBuffer && !IsNativeBuffer(bufferData, bufferLength)) + { + Contract.Assert(false, + "WebSocketGetAction MUST return a pointer within the pinned internal buffer."); + // Indicates a violation in the contract with native Websocket.dll and could indicate + // memory corruption because the internal buffer is shared between managed and native code + throw new AccessViolationException(); + } + } + + if (!nonZeroBufferFound && + action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.NoAction && + action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateReceiveComplete && + action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateSendComplete) + { + Contract.Assert(false, "At least one 'dataBuffer.Buffer' MUST NOT be NULL."); + } + } + + private static int GetNativeSendBufferSize(int sendBufferSize, bool isServerBuffer) + { + return isServerBuffer ? MinSendBufferSize : sendBufferSize; + } + + internal static void UnwrapWebSocketBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, + UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, + out IntPtr bufferData, + out uint bufferLength) + { + bufferData = IntPtr.Zero; + bufferLength = 0; + + switch (bufferType) + { + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close: + bufferData = buffer.CloseStatus.ReasonData; + bufferLength = buffer.CloseStatus.ReasonLength; + break; + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.None: + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment: + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage: + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment: + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message: + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.PingPong: + case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UnsolicitedPong: + bufferData = buffer.Data.BufferData; + bufferLength = buffer.Data.BufferLength; + break; + default: + Contract.Assert(false, + string.Format(CultureInfo.InvariantCulture, + "BufferType '{0}' is invalid/unknown.", + bufferType)); + break; + } + } + + private void ThrowIfDisposed() + { + switch (_StateWhenDisposing) + { + case int.MinValue: + return; + case (int)WebSocketState.Closed: + case (int)WebSocketState.Aborted: + throw new WebSocketException(WebSocketError.InvalidState, + SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, typeof(WebSocketBase), _StateWhenDisposing)); + default: + throw new ObjectDisposedException(GetType().FullName); + } + } + + [Conditional("DEBUG"), Conditional("CONTRACTS_FULL")] + private void ValidateBufferedPayload() + { + Contract.Assert(_BufferedPayloadReceiveResult != null, + "'m_BufferedPayloadReceiveResult' MUST NOT be NULL."); + Contract.Assert(_BufferedPayloadReceiveResult.Count >= 0, + "'m_BufferedPayloadReceiveResult.Count' MUST NOT be negative."); + Contract.Assert(_PayloadOffset >= 0, "'m_PayloadOffset' MUST NOT be smaller than 0."); + Contract.Assert(_PayloadOffset <= _PayloadBuffer.Count, + "'m_PayloadOffset' MUST NOT be bigger than 'm_PayloadBuffer.Count'."); + Contract.Assert(_PayloadOffset + _BufferedPayloadReceiveResult.Count <= _PayloadBuffer.Count, + "'m_PayloadOffset + m_PayloadBytesBuffered' MUST NOT be bigger than 'm_PayloadBuffer.Count'."); + } + + private int GetOffset(IntPtr pBuffer) + { + Contract.Assert(pBuffer != IntPtr.Zero, "'pBuffer' MUST NOT be IntPtr.Zero."); + int offset = (int)(pBuffer.ToInt64() - _StartAddress + _InternalBuffer.Offset); + + Contract.Assert(offset >= 0, "'offset' MUST NOT be negative."); + return offset; + } + + [Pure] + private int GetMaxBufferSize() + { + return Math.Max(_ReceiveBufferSize, _SendBufferSize); + } + + internal bool IsInternalBuffer(byte[] buffer, int offset, int count) + { + Contract.Assert(buffer != null, "'buffer' MUST NOT be NULL."); + Contract.Assert(_InternalBuffer.Array != null, "'m_InternalBuffer.Array' MUST NOT be NULL."); + Contract.Assert(offset >= 0, "'offset' MUST NOT be negative."); + Contract.Assert(count >= 0, "'count' MUST NOT be negative."); + Contract.Assert(offset + count <= buffer.Length, "'offset + count' MUST NOT exceed 'buffer.Length'."); + + return object.ReferenceEquals(buffer, _InternalBuffer.Array); + } + + internal IntPtr ToIntPtr(int offset) + { + Contract.Assert(offset >= 0, "'offset' MUST NOT be negative."); + Contract.Assert(_StartAddress + offset <= _EndAddress, "'offset' is TOO BIG."); + return new IntPtr(_StartAddress + offset); + } + + private bool IsNativeBuffer(IntPtr pBuffer, uint bufferSize) + { + Contract.Assert(pBuffer != IntPtr.Zero, "'pBuffer' MUST NOT be NULL."); + Contract.Assert(bufferSize <= GetMaxBufferSize(), + "'bufferSize' MUST NOT be bigger than 'm_ReceiveBufferSize' and 'm_SendBufferSize'."); + + long nativeBufferStartAddress = pBuffer.ToInt64(); + long nativeBufferEndAddress = bufferSize + nativeBufferStartAddress; + + Contract.Assert(Marshal.UnsafeAddrOfPinnedArrayElement(_InternalBuffer.Array, _InternalBuffer.Offset).ToInt64() == _StartAddress, + "'m_InternalBuffer.Array' MUST be pinned for the whole lifetime of a WebSocket."); + + if (nativeBufferStartAddress >= _StartAddress && + nativeBufferStartAddress <= _EndAddress && + nativeBufferEndAddress >= _StartAddress && + nativeBufferEndAddress <= _EndAddress) + { + return true; + } + + return false; + } + + private void CleanUp() + { + if (_GCHandle.IsAllocated) + { + _GCHandle.Free(); + } + + ReleasePinnedSendBuffer(); + } + + internal static ArraySegment CreateInternalBufferArraySegment(int receiveBufferSize, int sendBufferSize, bool isServerBuffer) + { + Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, + "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + Contract.Assert(sendBufferSize >= MinSendBufferSize, + "'sendBufferSize' MUST be at least " + MinSendBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + + int internalBufferSize = GetInternalBufferSize(receiveBufferSize, sendBufferSize, isServerBuffer); + return new ArraySegment(new byte[internalBufferSize]); + } + + internal static void Validate(int count, int receiveBufferSize, int sendBufferSize, bool isServerBuffer) + { + Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, + "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + Contract.Assert(sendBufferSize >= MinSendBufferSize, + "'sendBufferSize' MUST be at least " + MinSendBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + + int minBufferSize = GetInternalBufferSize(receiveBufferSize, sendBufferSize, isServerBuffer); + if (count < minBufferSize) + { + throw new ArgumentOutOfRangeException("internalBuffer", + SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_InternalBuffer, minBufferSize)); + } + } + + private static int GetInternalBufferSize(int receiveBufferSize, int sendBufferSize, bool isServerBuffer) + { + Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, + "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + Contract.Assert(sendBufferSize >= MinSendBufferSize, + "'sendBufferSize' MUST be at least " + MinSendBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + + Contract.Assert(receiveBufferSize <= MaxBufferSize, + "'receiveBufferSize' MUST be less than or equal to " + MaxBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + Contract.Assert(sendBufferSize <= MaxBufferSize, + "'sendBufferSize' MUST be at less than or equal to " + MaxBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); + + int nativeSendBufferSize = GetNativeSendBufferSize(sendBufferSize, isServerBuffer); + return (2 * receiveBufferSize) + nativeSendBufferSize + NativeOverheadBufferSize + PropertyBufferSize; + } + + private static class SendBufferState + { + public const int None = 0; + public const int SendPayloadSpecified = 1; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs b/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs new file mode 100644 index 0000000000..a773179e21 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.AspNet.WebSockets +{ + [SuppressMessage("Microsoft.Design", + "CA1008:EnumsShouldHaveZeroValue", + Justification = "This enum is reflecting the IETF's WebSocket specification. " + + "'0' is a disallowed value for the close status code")] + public enum WebSocketCloseStatus + { + NormalClosure = 1000, + EndpointUnavailable = 1001, + ProtocolError = 1002, + InvalidMessageType = 1003, + Empty = 1005, + // AbnormalClosure = 1006, // 1006 is reserved and should never be used by user + InvalidPayloadData = 1007, + PolicyViolation = 1008, + MessageTooBig = 1009, + MandatoryExtension = 1010, + InternalServerError = 1011 + // TLSHandshakeFailed = 1015, // 1015 is reserved and should never be used by user + + // 0 - 999 Status codes in the range 0-999 are not used. + // 1000 - 1999 Status codes in the range 1000-1999 are reserved for definition by this protocol. + // 2000 - 2999 Status codes in the range 2000-2999 are reserved for use by extensions. + // 3000 - 3999 Status codes in the range 3000-3999 MAY be used by libraries and frameworks. The + // interpretation of these codes is undefined by this protocol. End applications MUST + // NOT use status codes in this range. + // 4000 - 4999 Status codes in the range 4000-4999 MAY be used by application code. The interpretaion + // of these codes is undefined by this protocol. + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketError.cs b/src/Microsoft.AspNet.WebSockets/WebSocketError.cs new file mode 100644 index 0000000000..473bb56349 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketError.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.WebSockets +{ + public enum WebSocketError + { + Success = 0, + InvalidMessageType = 1, + Faulted = 2, + NativeError = 3, + NotAWebSocket = 4, + UnsupportedVersion = 5, + UnsupportedProtocol = 6, + HeaderError = 7, + ConnectionClosedPrematurely = 8, + InvalidState = 9 + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketException.cs b/src/Microsoft.AspNet.WebSockets/WebSocketException.cs new file mode 100644 index 0000000000..64edc3d0cb --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketException.cs @@ -0,0 +1,155 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNet.WebSockets +{ +#if NET45 + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] +#endif + internal sealed class WebSocketException : Win32Exception + { + private WebSocketError _WebSocketErrorCode; + + public WebSocketException() + : this(Marshal.GetLastWin32Error()) + { + } + + public WebSocketException(WebSocketError error) + : this(error, GetErrorMessage(error)) + { + } + + public WebSocketException(WebSocketError error, string message) : base(message) + { + _WebSocketErrorCode = error; + } + + public WebSocketException(WebSocketError error, Exception innerException) + : this(error, GetErrorMessage(error), innerException) + { + } + + public WebSocketException(WebSocketError error, string message, Exception innerException) + : base(message, innerException) + { + _WebSocketErrorCode = error; + } + + public WebSocketException(int nativeError) + : base(nativeError) + { + _WebSocketErrorCode = !UnsafeNativeMethods.WebSocketProtocolComponent.Succeeded(nativeError) ? WebSocketError.NativeError : WebSocketError.Success; + this.SetErrorCodeOnError(nativeError); + } + + public WebSocketException(int nativeError, string message) + : base(nativeError, message) + { + _WebSocketErrorCode = !UnsafeNativeMethods.WebSocketProtocolComponent.Succeeded(nativeError) ? WebSocketError.NativeError : WebSocketError.Success; + this.SetErrorCodeOnError(nativeError); + } + + public WebSocketException(int nativeError, Exception innerException) + : base(SR.GetString(SR.net_WebSockets_Generic), innerException) + { + _WebSocketErrorCode = !UnsafeNativeMethods.WebSocketProtocolComponent.Succeeded(nativeError) ? WebSocketError.NativeError : WebSocketError.Success; + this.SetErrorCodeOnError(nativeError); + } + + public WebSocketException(WebSocketError error, int nativeError) + : this(error, nativeError, GetErrorMessage(error)) + { + } + + public WebSocketException(WebSocketError error, int nativeError, string message) + : base(message) + { + _WebSocketErrorCode = error; + this.SetErrorCodeOnError(nativeError); + } + + public WebSocketException(WebSocketError error, int nativeError, Exception innerException) + : this(error, nativeError, GetErrorMessage(error), innerException) + { + } + + public WebSocketException(WebSocketError error, int nativeError, string message, Exception innerException) + : base(message, innerException) + { + _WebSocketErrorCode = error; + this.SetErrorCodeOnError(nativeError); + } + + public WebSocketException(string message) + : base(message) + { + } + + public WebSocketException(string message, Exception innerException) + : base(message, innerException) + { + } + + public override int ErrorCode + { + get + { + return base.NativeErrorCode; + } + } + + public WebSocketError WebSocketErrorCode + { + get + { + return _WebSocketErrorCode; + } + } + + private static string GetErrorMessage(WebSocketError error) + { + // provide a canned message for the error type + switch (error) + { + case WebSocketError.InvalidMessageType: + return SR.GetString(SR.net_WebSockets_InvalidMessageType_Generic, + typeof(WebSocket).Name + WebSocketBase.Methods.CloseAsync, + typeof(WebSocket).Name + WebSocketBase.Methods.CloseOutputAsync); + case WebSocketError.Faulted: + return SR.GetString(SR.net_Websockets_WebSocketBaseFaulted); + case WebSocketError.NotAWebSocket: + return SR.GetString(SR.net_WebSockets_NotAWebSocket_Generic); + case WebSocketError.UnsupportedVersion: + return SR.GetString(SR.net_WebSockets_UnsupportedWebSocketVersion_Generic); + case WebSocketError.UnsupportedProtocol: + return SR.GetString(SR.net_WebSockets_UnsupportedProtocol_Generic); + case WebSocketError.HeaderError: + return SR.GetString(SR.net_WebSockets_HeaderError_Generic); + case WebSocketError.ConnectionClosedPrematurely: + return SR.GetString(SR.net_WebSockets_ConnectionClosedPrematurely_Generic); + case WebSocketError.InvalidState: + return SR.GetString(SR.net_WebSockets_InvalidState_Generic); + default: + return SR.GetString(SR.net_WebSockets_Generic); + } + } + + // Set the error code only if there is an error (i.e. nativeError >= 0). Otherwise the code blows up on deserialization + // as the Exception..ctor() throws on setting HResult to 0. The default for HResult is -2147467259. + private void SetErrorCodeOnError(int nativeError) + { + if (!UnsafeNativeMethods.WebSocketProtocolComponent.Succeeded(nativeError)) + { + this.HResult = nativeError; + } + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs b/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs new file mode 100644 index 0000000000..abcbd12865 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs @@ -0,0 +1,14 @@ +#if NET45 +using Microsoft.AspNet.WebSockets; + +namespace Owin +{ + public static class WebSocketExtensions + { + public static IAppBuilder UseWebSockets(this IAppBuilder app) + { + return app.Use(); + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs b/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs new file mode 100644 index 0000000000..3479e137fa --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs @@ -0,0 +1,522 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.IO; +using System.Runtime.CompilerServices; +#if NET45 +using System.Security.Cryptography; +#endif +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.WebSockets +{ + internal static class WebSocketHelpers + { + internal const string SecWebSocketKeyGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + internal const string WebSocketUpgradeToken = "websocket"; + internal const int DefaultReceiveBufferSize = 16 * 1024; + internal const int DefaultClientSendBufferSize = 16 * 1024; + internal const int MaxControlFramePayloadLength = 123; + + // RFC 6455 requests WebSocket clients to let the server initiate the TCP close to avoid that client sockets + // end up in TIME_WAIT-state + // + // After both sending and receiving a Close message, an endpoint considers the WebSocket connection closed and + // MUST close the underlying TCP connection. The server MUST close the underlying TCP connection immediately; + // the client SHOULD wait for the server to close the connection but MAY close the connection at any time after + // sending and receiving a Close message, e.g., if it has not received a TCP Close from the server in a + // reasonable time period. + internal const int ClientTcpCloseTimeout = 1000; // 1s + + private const int CloseStatusCodeAbort = 1006; + private const int CloseStatusCodeFailedTLSHandshake = 1015; + private const int InvalidCloseStatusCodesFrom = 0; + private const int InvalidCloseStatusCodesTo = 999; + private const string Separators = "()<>@,;:\\\"/[]?={} "; + + internal static readonly ArraySegment EmptyPayload = new ArraySegment(new byte[] { }, 0, 0); + private static readonly Random KeyGenerator = new Random(); + +/* + internal static Task AcceptWebSocketAsync(HttpListenerContext context, + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + { + WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); + WebSocketHelpers.ValidateArraySegment(internalBuffer, "internalBuffer"); + WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + + return AcceptWebSocketAsyncCore(context, subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer); + } + + private static async Task AcceptWebSocketAsyncCore(HttpListenerContext context, + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + { + HttpListenerWebSocketContext webSocketContext = null; + /*if (Logging.On) + { + Logging.Enter(Logging.WebSockets, context, "AcceptWebSocketAsync", ""); + }* / + + try + { + // get property will create a new response if one doesn't exist. + HttpListenerResponse response = context.Response; + HttpListenerRequest request = context.Request; + ValidateWebSocketHeaders(context); + + string secWebSocketVersion = request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; + + // Optional for non-browser client + string origin = request.Headers[HttpKnownHeaderNames.Origin]; + + List secWebSocketProtocols = new List(); + string outgoingSecWebSocketProtocolString; + bool shouldSendSecWebSocketProtocolHeader = + WebSocketHelpers.ProcessWebSocketProtocolHeader( + request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol], + subProtocol, + out outgoingSecWebSocketProtocolString); + + if (shouldSendSecWebSocketProtocolHeader) + { + secWebSocketProtocols.Add(outgoingSecWebSocketProtocolString); + response.Headers.Add(HttpKnownHeaderNames.SecWebSocketProtocol, + outgoingSecWebSocketProtocolString); + } + + // negotiate the websocket key return value + string secWebSocketKey = request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); + + response.Headers.Add(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); + response.Headers.Add(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); + response.Headers.Add(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); + + response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; // HTTP 101 + response.ComputeCoreHeaders(); + ulong hresult = SendWebSocketHeaders(response); + if (hresult != 0) + { + throw new WebSocketException((int)hresult, + SR.GetString(SR.net_WebSockets_NativeSendResponseHeaders, + WebSocketHelpers.MethodNames.AcceptWebSocketAsync, + hresult)); + } + + await response.OutputStream.FlushAsync().SuppressContextFlow(); // TODO:??? FlushAsync was never implemented + + HttpResponseStream responseStream = response.OutputStream as HttpResponseStream; + Contract.Assert(responseStream != null, "'responseStream' MUST be castable to System.Net.HttpResponseStream."); + ((HttpResponseStream)response.OutputStream).SwitchToOpaqueMode(); + HttpRequestStream requestStream = new HttpRequestStream(context); + requestStream.SwitchToOpaqueMode(); + WebSocketHttpListenerDuplexStream webSocketStream = + new WebSocketHttpListenerDuplexStream(requestStream, responseStream, context); + WebSocket webSocket = WebSocket.CreateServerWebSocket(webSocketStream, + subProtocol, + receiveBufferSize, + keepAliveInterval, + internalBuffer); + + webSocketContext = new HttpListenerWebSocketContext( + request.Url, + request.Headers, + request.Cookies, + context.User, + request.IsAuthenticated, + request.IsLocal, + request.IsSecureConnection, + origin, + secWebSocketProtocols.AsReadOnly(), + secWebSocketVersion, + secWebSocketKey, + webSocket); + + if (Logging.On) + { + Logging.Associate(Logging.WebSockets, context, webSocketContext); + Logging.Associate(Logging.WebSockets, webSocketContext, webSocket); + } + } + catch (Exception ex) + { + if (Logging.On) + { + Logging.Exception(Logging.WebSockets, context, "AcceptWebSocketAsync", ex); + } + throw; + } + finally + { + if (Logging.On) + { + Logging.Exit(Logging.WebSockets, context, "AcceptWebSocketAsync", ""); + } + } + return webSocketContext; + } + +*/ + [SuppressMessage("Microsoft.Cryptographic.Standard", "CA5354:SHA1CannotBeUsed", + Justification = "SHA1 used only for hashing purposes, not for crypto.")] + internal static string GetSecWebSocketAcceptString(string secWebSocketKey) + { + string retVal; +#if NET45 + // SHA1 used only for hashing purposes, not for crypto. Check here for FIPS compat. + using (SHA1 sha1 = SHA1.Create()) + { + string acceptString = string.Concat(secWebSocketKey, WebSocketHelpers.SecWebSocketKeyGuid); + byte[] toHash = Encoding.UTF8.GetBytes(acceptString); + retVal = Convert.ToBase64String(sha1.ComputeHash(toHash)); + } +#endif + return retVal; + } + + internal static string GetTraceMsgForParameters(int offset, int count, CancellationToken cancellationToken) + { + return string.Format(CultureInfo.InvariantCulture, + "offset: {0}, count: {1}, cancellationToken.CanBeCanceled: {2}", + offset, + count, + cancellationToken.CanBeCanceled); + } + + // return value here signifies if a Sec-WebSocket-Protocol header should be returned by the server. + internal static bool ProcessWebSocketProtocolHeader(string clientSecWebSocketProtocol, + string subProtocol, + out string acceptProtocol) + { + acceptProtocol = string.Empty; + if (string.IsNullOrEmpty(clientSecWebSocketProtocol)) + { + // client hasn't specified any Sec-WebSocket-Protocol header + if (subProtocol != null) + { + // If the server specified _anything_ this isn't valid. + throw new WebSocketException(WebSocketError.UnsupportedProtocol, + SR.GetString(SR.net_WebSockets_ClientAcceptingNoProtocols, subProtocol)); + } + // Treat empty and null from the server as the same thing here, server should not send headers. + return false; + } + + // here, we know the client specified something and it's non-empty. + + if (subProtocol == null) + { + // client specified some protocols, server specified 'null'. So server should send headers. + return true; + } + + // here, we know that the client has specified something, it's not empty + // and the server has specified exactly one protocol + + string[] requestProtocols = clientSecWebSocketProtocol.Split(new char[] { ',' }, + StringSplitOptions.RemoveEmptyEntries); + acceptProtocol = subProtocol; + + // client specified protocols, serverOptions has exactly 1 non-empty entry. Check that + // this exists in the list the client specified. + for (int i = 0; i < requestProtocols.Length; i++) + { + string currentRequestProtocol = requestProtocols[i].Trim(); + if (string.Compare(acceptProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase) == 0) + { + return true; + } + } + + throw new WebSocketException(WebSocketError.UnsupportedProtocol, + SR.GetString(SR.net_WebSockets_AcceptUnsupportedProtocol, + clientSecWebSocketProtocol, + subProtocol)); + } + + internal static ConfiguredTaskAwaitable SuppressContextFlow(this Task task) + { + // We don't flow the synchronization context within WebSocket.xxxAsync - but the calling application + // can decide whether the completion callback for the task returned from WebSocket.xxxAsync runs + // under the caller's synchronization context. + return task.ConfigureAwait(false); + } + + internal static ConfiguredTaskAwaitable SuppressContextFlow(this Task task) + { + // We don't flow the synchronization context within WebSocket.xxxAsync - but the calling application + // can decide whether the completion callback for the task returned from WebSocket.xxxAsync runs + // under the caller's synchronization context. + return task.ConfigureAwait(false); + } + + internal static void ValidateBuffer(byte[] buffer, int offset, int count) + { + if (buffer == null) + { + throw new ArgumentNullException("buffer"); + } + + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException("offset"); + } + + if (count < 0 || count > (buffer.Length - offset)) + { + throw new ArgumentOutOfRangeException("count"); + } + } + /* + private static unsafe ulong SendWebSocketHeaders(HttpListenerResponse response) + { + return response.SendHeaders(null, null, + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE | + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA | + UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA, + true); + } + private static void ValidateWebSocketHeaders(HttpListenerContext context) + { + EnsureHttpSysSupportsWebSockets(); + + if (!context.Request.IsWebSocketRequest) + { + throw new WebSocketException(WebSocketError.NotAWebSocket, + SR.GetString(SR.net_WebSockets_AcceptNotAWebSocket, + WebSocketHelpers.MethodNames.ValidateWebSocketHeaders, + HttpKnownHeaderNames.Connection, + HttpKnownHeaderNames.Upgrade, + WebSocketHelpers.WebSocketUpgradeToken, + context.Request.Headers[HttpKnownHeaderNames.Upgrade])); + } + + string secWebSocketVersion = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; + if (string.IsNullOrEmpty(secWebSocketVersion)) + { + throw new WebSocketException(WebSocketError.HeaderError, + SR.GetString(SR.net_WebSockets_AcceptHeaderNotFound, + WebSocketHelpers.MethodNames.ValidateWebSocketHeaders, + HttpKnownHeaderNames.SecWebSocketVersion)); + } + + if (string.Compare(secWebSocketVersion, WebSocketProtocolComponent.SupportedVersion, StringComparison.OrdinalIgnoreCase) != 0) + { + throw new WebSocketException(WebSocketError.UnsupportedVersion, + SR.GetString(SR.net_WebSockets_AcceptUnsupportedWebSocketVersion, + WebSocketHelpers.MethodNames.ValidateWebSocketHeaders, + secWebSocketVersion, + WebSocketProtocolComponent.SupportedVersion)); + } + + if (string.IsNullOrWhiteSpace(context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey])) + { + throw new WebSocketException(WebSocketError.HeaderError, + SR.GetString(SR.net_WebSockets_AcceptHeaderNotFound, + WebSocketHelpers.MethodNames.ValidateWebSocketHeaders, + HttpKnownHeaderNames.SecWebSocketKey)); + } + } + */ + + internal static void ValidateSubprotocol(string subProtocol) + { + if (string.IsNullOrWhiteSpace(subProtocol)) + { + throw new ArgumentException(SR.GetString(SR.net_WebSockets_InvalidEmptySubProtocol), "subProtocol"); + } + + char[] chars = subProtocol.ToCharArray(); + string invalidChar = null; + int i = 0; + while (i < chars.Length) + { + char ch = chars[i]; + if (ch < 0x21 || ch > 0x7e) + { + invalidChar = string.Format(CultureInfo.InvariantCulture, "[{0}]", (int)ch); + break; + } + + if (!char.IsLetterOrDigit(ch) && + Separators.IndexOf(ch) >= 0) + { + invalidChar = ch.ToString(); + break; + } + + i++; + } + + if (invalidChar != null) + { + throw new ArgumentException(SR.GetString(SR.net_WebSockets_InvalidCharInProtocolString, subProtocol, invalidChar), + "subProtocol"); + } + } + + internal static void ValidateCloseStatus(WebSocketCloseStatus closeStatus, string statusDescription) + { + if (closeStatus == WebSocketCloseStatus.Empty && !string.IsNullOrEmpty(statusDescription)) + { + throw new ArgumentException(SR.GetString(SR.net_WebSockets_ReasonNotNull, + statusDescription, + WebSocketCloseStatus.Empty), + "statusDescription"); + } + + int closeStatusCode = (int)closeStatus; + + if ((closeStatusCode >= InvalidCloseStatusCodesFrom && + closeStatusCode <= InvalidCloseStatusCodesTo) || + closeStatusCode == CloseStatusCodeAbort || + closeStatusCode == CloseStatusCodeFailedTLSHandshake) + { + // CloseStatus 1006 means Aborted - this will never appear on the wire and is reflected by calling WebSocket.Abort + throw new ArgumentException(SR.GetString(SR.net_WebSockets_InvalidCloseStatusCode, + closeStatusCode), + "closeStatus"); + } + + int length = 0; + if (!string.IsNullOrEmpty(statusDescription)) + { + length = UTF8Encoding.UTF8.GetByteCount(statusDescription); + } + + if (length > WebSocketHelpers.MaxControlFramePayloadLength) + { + throw new ArgumentException(SR.GetString(SR.net_WebSockets_InvalidCloseStatusDescription, + statusDescription, + WebSocketHelpers.MaxControlFramePayloadLength), + "statusDescription"); + } + } + + internal static void ValidateOptions(string subProtocol, + int receiveBufferSize, + int sendBufferSize, + TimeSpan keepAliveInterval) + { + // We allow the subProtocol to be null. Validate if it is not null. + if (subProtocol != null) + { + ValidateSubprotocol(subProtocol); + } + + ValidateBufferSizes(receiveBufferSize, sendBufferSize); + + // -1 + if (keepAliveInterval < Timeout.InfiniteTimeSpan) + { + throw new ArgumentOutOfRangeException("keepAliveInterval", keepAliveInterval, + SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, Timeout.InfiniteTimeSpan.ToString())); + } + } + + internal static void ValidateBufferSizes(int receiveBufferSize, int sendBufferSize) + { + if (receiveBufferSize < WebSocketBuffer.MinReceiveBufferSize) + { + throw new ArgumentOutOfRangeException("receiveBufferSize", receiveBufferSize, + SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, WebSocketBuffer.MinReceiveBufferSize)); + } + + if (sendBufferSize < WebSocketBuffer.MinSendBufferSize) + { + throw new ArgumentOutOfRangeException("sendBufferSize", sendBufferSize, + SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, WebSocketBuffer.MinSendBufferSize)); + } + + if (receiveBufferSize > WebSocketBuffer.MaxBufferSize) + { + throw new ArgumentOutOfRangeException("receiveBufferSize", receiveBufferSize, + SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooBig, + "receiveBufferSize", + receiveBufferSize, + WebSocketBuffer.MaxBufferSize)); + } + + if (sendBufferSize > WebSocketBuffer.MaxBufferSize) + { + throw new ArgumentOutOfRangeException("sendBufferSize", sendBufferSize, + SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooBig, + "sendBufferSize", + sendBufferSize, + WebSocketBuffer.MaxBufferSize)); + } + } + + internal static void ValidateInnerStream(Stream innerStream) + { + if (innerStream == null) + { + throw new ArgumentNullException("innerStream"); + } + + if (!innerStream.CanRead) + { + throw new ArgumentException(SR.GetString(SR.NotReadableStream), "innerStream"); + } + + if (!innerStream.CanWrite) + { + throw new ArgumentException(SR.GetString(SR.NotWriteableStream), "innerStream"); + } + } + + internal static void ThrowIfConnectionAborted(Stream connection, bool read) + { + if ((!read && !connection.CanWrite) || + (read && !connection.CanRead)) + { + throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely); + } + } + + internal static void ThrowPlatformNotSupportedException_WSPC() + { + throw new PlatformNotSupportedException(SR.GetString(SR.net_WebSockets_UnsupportedPlatform)); + } + + internal static void ValidateArraySegment(ArraySegment arraySegment, string parameterName) + { + Contract.Requires(!string.IsNullOrEmpty(parameterName), "'parameterName' MUST NOT be NULL or string.Empty"); + + if (arraySegment.Array == null) + { + throw new ArgumentNullException(parameterName + ".Array"); + } + + if (arraySegment.Offset < 0 || arraySegment.Offset > arraySegment.Array.Length) + { + throw new ArgumentOutOfRangeException(parameterName + ".Offset"); + } + if (arraySegment.Count < 0 || arraySegment.Count > (arraySegment.Array.Length - arraySegment.Offset)) + { + throw new ArgumentOutOfRangeException(parameterName + ".Count"); + } + } + + internal static class MethodNames + { + internal const string AcceptWebSocketAsync = "AcceptWebSocketAsync"; + internal const string ValidateWebSocketHeaders = "ValidateWebSocketHeaders"; + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs b/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs new file mode 100644 index 0000000000..1661721a14 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs @@ -0,0 +1,15 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.WebSockets +{ + public enum WebSocketMessageType + { + Text = 0x1, + Binary = 0x2, + Close = 0x8, + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs b/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs new file mode 100644 index 0000000000..7a77a6a4f6 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Owin; + +namespace Microsoft.AspNet.WebSockets +{ + using AppFunc = Func, Task>; + using OpaqueUpgrade = + Action + < + IDictionary, // Parameters + Func // OpaqueFunc callback + < + IDictionary, // Opaque environment + Task // Complete + > + >; + using WebSocketAccept = + Action + < + IDictionary, // WebSocket Accept parameters + Func // WebSocketFunc callback + < + IDictionary, // WebSocket environment + Task // Complete + > + >; + using WebSocketFunc = + Func + < + IDictionary, // WebSocket Environment + Task // Complete + >; + + public class WebSocketMiddleware + { + private AppFunc _next; + + public WebSocketMiddleware(AppFunc next) + { + _next = next; + } + + public Task Invoke(IDictionary environment) + { + IOwinContext context = new OwinContext(environment); + // Detect if an opaque upgrade is available, and if websocket upgrade headers are present. + // If so, add a websocket upgrade. + OpaqueUpgrade upgrade = context.Get("opaque.Upgrade"); + if (upgrade != null) + { + // Headers and values: + // Connection: Upgrade + // Upgrade: WebSocket + // Sec-WebSocket-Version: (WebSocketProtocolComponent.SupportedVersion) + // Sec-WebSocket-Key: (hash, see WebSocketHelpers.GetSecWebSocketAcceptString) + // Sec-WebSocket-Protocol: (optional, list) + IList connectionHeaders = context.Request.Headers.GetCommaSeparatedValues(HttpKnownHeaderNames.Connection); // "Upgrade, KeepAlive" + string upgradeHeader = context.Request.Headers[HttpKnownHeaderNames.Upgrade]; + string versionHeader = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; + string keyHeader = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + + if (connectionHeaders != null && connectionHeaders.Count > 0 + && connectionHeaders.Contains(HttpKnownHeaderNames.Upgrade, StringComparer.OrdinalIgnoreCase) + && string.Equals(upgradeHeader, WebSocketHelpers.WebSocketUpgradeToken, StringComparison.OrdinalIgnoreCase) + && string.Equals(versionHeader, UnsafeNativeMethods.WebSocketProtocolComponent.SupportedVersion, StringComparison.OrdinalIgnoreCase) + && !string.IsNullOrWhiteSpace(keyHeader)) + { + environment["websocket.Accept"] = new WebSocketAccept(new UpgradeHandshake(context, upgrade).AcceptWebSocket); + } + } + + return _next(environment); + } + + private class UpgradeHandshake + { + private IOwinContext _context; + private OpaqueUpgrade _upgrade; + private WebSocketFunc _webSocketFunc; + + private string _subProtocol; + private int _receiveBufferSize = WebSocketHelpers.DefaultReceiveBufferSize; + private TimeSpan _keepAliveInterval = WebSocket.DefaultKeepAliveInterval; + private ArraySegment _internalBuffer; + + internal UpgradeHandshake(IOwinContext context, OpaqueUpgrade upgrade) + { + _context = context; + _upgrade = upgrade; + } + + internal void AcceptWebSocket(IDictionary options, WebSocketFunc webSocketFunc) + { + _webSocketFunc = webSocketFunc; + + // Get options + object temp; + if (options != null && options.TryGetValue("websocket.SubProtocol", out temp)) + { + _subProtocol = temp as string; + } + if (options != null && options.TryGetValue("websocket.ReceiveBufferSize", out temp)) + { + _receiveBufferSize = (int)temp; + } + if (options != null && options.TryGetValue("websocket.KeepAliveInterval", out temp)) + { + _keepAliveInterval = (TimeSpan)temp; + } + if (options != null && options.TryGetValue("websocket.Buffer", out temp)) + { + _internalBuffer = (ArraySegment)temp; + } + else + { + _internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(_receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + } + + // Set WebSocket upgrade response headers + + string outgoingSecWebSocketProtocolString; + bool shouldSendSecWebSocketProtocolHeader = + WebSocketHelpers.ProcessWebSocketProtocolHeader( + _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol], + _subProtocol, + out outgoingSecWebSocketProtocolString); + + if (shouldSendSecWebSocketProtocolHeader) + { + _context.Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = outgoingSecWebSocketProtocolString; + } + + string secWebSocketKey = _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); + + _context.Response.Headers[HttpKnownHeaderNames.Connection] = HttpKnownHeaderNames.Upgrade; + _context.Response.Headers[HttpKnownHeaderNames.Upgrade] = WebSocketHelpers.WebSocketUpgradeToken; + _context.Response.Headers[HttpKnownHeaderNames.SecWebSocketAccept] = secWebSocketAccept; + + _context.Response.StatusCode = 101; // Switching Protocols; + + _upgrade(options, OpaqueCallback); + } + + internal async Task OpaqueCallback(IDictionary opaqueEnv) + { + // Create WebSocket wrapper around the opaque env + WebSocket webSocket = CreateWebSocket(opaqueEnv); + OwinWebSocketWrapper wrapper = new OwinWebSocketWrapper(webSocket, (CancellationToken)opaqueEnv["opaque.CallCancelled"]); + await _webSocketFunc(wrapper.Environment); + // Close down the WebSocekt, gracefully if possible + await wrapper.CleanupAsync(); + } + + private WebSocket CreateWebSocket(IDictionary opaqueEnv) + { + Stream stream = (Stream)opaqueEnv["opaque.Stream"]; + return new ServerWebSocket(stream, _subProtocol, _receiveBufferSize, _keepAliveInterval, _internalBuffer); + } + } + } +} diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs b/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs new file mode 100644 index 0000000000..a48be62a2d --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.AspNet.WebSockets +{ + public class WebSocketReceiveResult + { + public WebSocketReceiveResult(int count, WebSocketMessageType messageType, bool endOfMessage) + : this(count, messageType, endOfMessage, null, null) + { + } + + public WebSocketReceiveResult(int count, + WebSocketMessageType messageType, + bool endOfMessage, + WebSocketCloseStatus? closeStatus, + string closeStatusDescription) + { + if (count < 0) + { + throw new ArgumentOutOfRangeException("count"); + } + + this.Count = count; + this.EndOfMessage = endOfMessage; + this.MessageType = messageType; + this.CloseStatus = closeStatus; + this.CloseStatusDescription = closeStatusDescription; + } + + public int Count { get; private set; } + public bool EndOfMessage { get; private set; } + public WebSocketMessageType MessageType { get; private set; } + public WebSocketCloseStatus? CloseStatus { get; private set; } + public string CloseStatusDescription { get; private set; } + + internal WebSocketReceiveResult Copy(int count) + { + Contract.Assert(count >= 0, "'count' MUST NOT be negative."); + Contract.Assert(count <= this.Count, "'count' MUST NOT be bigger than 'this.Count'."); + this.Count -= count; + return new WebSocketReceiveResult(count, + this.MessageType, + this.Count == 0 && this.EndOfMessage, + this.CloseStatus, + this.CloseStatusDescription); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketState.cs b/src/Microsoft.AspNet.WebSockets/WebSocketState.cs new file mode 100644 index 0000000000..3c58d00a20 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/WebSocketState.cs @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNet.WebSockets +{ + public enum WebSocketState + { + None = 0, + Connecting = 1, + Open = 2, + CloseSent = 3, // WebSocket close handshake started form local endpoint + CloseReceived = 4, // WebSocket close message received from remote endpoint. Waiting for app to call close + Closed = 5, + Aborted = 6, + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/build.cmd b/src/Microsoft.AspNet.WebSockets/build.cmd new file mode 100644 index 0000000000..110694d575 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/build.cmd @@ -0,0 +1,3 @@ +rem set TARGET_FRAMEWORK=k10 +@call ..\..\packages\ProjectK.0.0.1-pre-30121-096\tools\k build +pause \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs new file mode 100644 index 0000000000..861c9e31ab --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -0,0 +1,31 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +#if !NET45 + +namespace Microsoft.Win32.SafeHandles +{ + using System; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + + // Class of safe handle which uses 0 or -1 as an invalid handle. + [System.Security.SecurityCritical] // auto-generated_required + internal abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle + { + protected SafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) + : base(IntPtr.Zero, ownsHandle) + { + } + + public override bool IsInvalid + { + [System.Security.SecurityCritical] + get { return handle == new IntPtr(0) || handle == new IntPtr(-1); } + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs b/src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs new file mode 100644 index 0000000000..c32cafb4e1 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs @@ -0,0 +1,16 @@ +#if !NET45 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System +{ + internal class AccessViolationException : SystemException + { + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs new file mode 100644 index 0000000000..108303ee2c --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +#if !NET45 + +using System.Runtime.InteropServices; +using System.Text; + +namespace System.ComponentModel +{ + internal class Win32Exception : ExternalException + { + /// + /// Represents the Win32 error code associated with this exception. This + /// field is read-only. + /// + private readonly int nativeErrorCode; + + /// + /// Initializes a new instance of the class with the last Win32 error + /// that occured. + /// + public Win32Exception() + : this(Marshal.GetLastWin32Error()) + { + } + /// + /// Initializes a new instance of the class with the specified error. + /// + public Win32Exception(int error) + : this(error, GetErrorMessage(error)) + { + } + /// + /// Initializes a new instance of the class with the specified error and the + /// specified detailed description. + /// + public Win32Exception(int error, string message) + : base(message) + { + nativeErrorCode = error; + } + + /// + /// Initializes a new instance of the Exception class with a specified error message. + /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. + /// + public Win32Exception(string message) + : this(Marshal.GetLastWin32Error(), message) + { + } + + /// + /// Initializes a new instance of the Exception class with a specified error message and a + /// reference to the inner exception that is the cause of this exception. + /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. + /// + public Win32Exception(string message, Exception innerException) + : base(message, innerException) + { + nativeErrorCode = Marshal.GetLastWin32Error(); + } + + + /// + /// Represents the Win32 error code associated with this exception. This + /// field is read-only. + /// + public int NativeErrorCode + { + get + { + return nativeErrorCode; + } + } + + private static string GetErrorMessage(int error) + { + //get the system error message... + string errorMsg = ""; + StringBuilder sb = new StringBuilder(256); + int result = SafeNativeMethods.FormatMessage( + SafeNativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS | + SafeNativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | + SafeNativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY, + IntPtr.Zero, (uint)error, 0, sb, sb.Capacity + 1, + null); + if (result != 0) + { + int i = sb.Length; + while (i > 0) + { + char ch = sb[i - 1]; + if (ch > 32 && ch != '.') break; + i--; + } + errorMsg = sb.ToString(0, i); + } + else + { + errorMsg = "Unknown error (0x" + Convert.ToString(error, 16) + ")"; + } + + return errorMsg; + } + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs new file mode 100644 index 0000000000..98303d48b8 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +#if !NET45 + +namespace System +{ + internal static class ExternDll + { + public const string Kernel32 = "kernel32.dll"; + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs new file mode 100644 index 0000000000..21d82b1de4 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs @@ -0,0 +1,98 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +/*============================================================================= +** +** Class: ExternalException +** +** +** Purpose: Exception base class for all errors from Interop or Structured +** Exception Handling code. +** +** +=============================================================================*/ + +#if !NET45 + +namespace System.Runtime.InteropServices +{ + using System; + using System.Globalization; + + // Base exception for COM Interop errors &; Structured Exception Handler + // exceptions. + // + internal class ExternalException : Exception + { + public ExternalException() + { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message) + : base(message) + { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message, Exception inner) + : base(message, inner) + { + SetErrorCode(__HResults.E_FAIL); + } + + public ExternalException(String message, int errorCode) + : base(message) + { + SetErrorCode(errorCode); + } + + private void SetErrorCode(int errorCode) + { + HResult = ErrorCode; + } + + private static class __HResults + { + internal const int E_FAIL = unchecked((int)0x80004005); + } + + public virtual int ErrorCode + { + get + { + return HResult; + } + } + + public override String ToString() + { + String message = Message; + String s; + String _className = GetType().ToString(); + s = _className + " (0x" + HResult.ToString("X8", CultureInfo.InvariantCulture) + ")"; + + if (!(String.IsNullOrEmpty(message))) + { + s = s + ": " + message; + } + + Exception _innerException = InnerException; + + if (_innerException != null) + { + s = s + " ---> " + _innerException.ToString(); + } + + + if (StackTrace != null) + s += Environment.NewLine + StackTrace; + + return s; + } + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs new file mode 100644 index 0000000000..969d273fa8 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +#if !NET45 +using System.Runtime.InteropServices; +using System.Text; + +namespace System +{ + internal static class SafeNativeMethods + { + public const int + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, + FORMAT_MESSAGE_FROM_STRING = 0x00000400, + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; + + [DllImport(ExternDll.Kernel32, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] + public static unsafe extern int FormatMessage(int dwFlags, IntPtr lpSource_mustBeNull, uint dwMessageId, + int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr[] arguments); + + } +} +#endif diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs b/src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs new file mode 100644 index 0000000000..4b6c66b4a4 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs @@ -0,0 +1,16 @@ +#if !NET45 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System +{ + internal class SystemException : Exception + { + } +} + +#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/packages.config b/src/Microsoft.AspNet.WebSockets/packages.config new file mode 100644 index 0000000000..fb47f58ced --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/project.json b/src/Microsoft.AspNet.WebSockets/project.json new file mode 100644 index 0000000000..943893dbd2 --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/project.json @@ -0,0 +1,17 @@ +{ + "version": "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*" + }, + "compilationOptions" : { "allowUnsafe": true }, + "configurations": + { + "net45" : { + "dependencies": { + "Owin": "1.0", + "Microsoft.Owin": "2.1.0" + } + } + } +} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs b/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs new file mode 100644 index 0000000000..3bd1cc9f00 --- /dev/null +++ b/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs @@ -0,0 +1,47 @@ +// +// Copyright 2011-2012 Katana contributors +// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Security.Principal; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Security.Windows.Tests +{ + using AppFunc = Func, Task>; + + // This middleware can be placed at the end of a chain of pass-through auth schemes if at least one type of auth is required. + public class DenyAnonymous + { + private readonly AppFunc _nextApp; + + public DenyAnonymous(AppFunc nextApp) + { + _nextApp = nextApp; + } + + public async Task Invoke(IDictionary env) + { + if (env.Get("server.User") == null) + { + env["owin.ResponseStatusCode"] = 401; + return; + } + + await _nextApp(env); + } + } +} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs b/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs new file mode 100644 index 0000000000..a1a6e3577a --- /dev/null +++ b/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Linq; +using System.Text; + +namespace System.Collections.Generic +{ + internal static class DictionaryExtensions + { + internal static void Append(this IDictionary dictionary, string key, string value) + { + string[] orriginalValues; + if (dictionary.TryGetValue(key, out orriginalValues)) + { + string[] newValues = new string[orriginalValues.Length + 1]; + orriginalValues.CopyTo(newValues, 0); + newValues[newValues.Length - 1] = value; + dictionary[key] = newValues; + } + else + { + dictionary[key] = new string[] { value }; + } + } + + internal static string Get(this IDictionary dictionary, string key) + { + string[] values; + if (dictionary.TryGetValue(key, out values)) + { + return string.Join(", ", values); + } + return null; + } + + internal static T Get(this IDictionary dictionary, string key, T fallback = default(T)) + { + object values; + if (dictionary.TryGetValue(key, out values)) + { + return (T)values; + } + return fallback; + } + } +} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs new file mode 100644 index 0000000000..e097a7e65b --- /dev/null +++ b/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs @@ -0,0 +1,244 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Security.Authentication.ExtendedProtection; +using System.Threading.Tasks; +using Microsoft.AspNet.Server.WebListener; +using Xunit; + +namespace Microsoft.AspNet.Security.Windows.Tests +{ + using AppFunc = Func, Task>; + + public class DigestTests + { + private const string Address = "http://localhost:8080/"; + private const string SecureAddress = "https://localhost:9090/"; + private const int DefaultStatusCode = 201; + + [Fact] + public async Task Digest_PartialMatch_PassedThrough() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); + IDictionary emptyEnv = CreateEmptyRequest("Authorization", "Digestion blablabla"); + await windowsAuth.Invoke(emptyEnv); + + Assert.Equal(DefaultStatusCode, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(0, responseHeaders.Count); + } + + [Fact] + public async Task Digest_BadData_400() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); + IDictionary emptyEnv = CreateEmptyRequest("Authorization", "Digest blablabla"); + await windowsAuth.Invoke(emptyEnv); + + Assert.Equal(400, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(0, responseHeaders.Count); + } + + [Fact] + public async Task Digest_AppSets401_401WithChallenge() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = AuthTypes.Digest; + IDictionary emptyEnv = CreateEmptyRequest(); + await windowsAuth.Invoke(emptyEnv); + FireOnSendingHeadersActions(emptyEnv); + + Assert.Equal(401, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(1, responseHeaders.Count); + Assert.NotNull(responseHeaders.Get("www-authenticate")); + Assert.True(responseHeaders.Get("www-authenticate").StartsWith("Digest ")); + } + + [Fact] + public async Task Digest_CbtOptionalButNotPresent_401WithChallenge() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = AuthTypes.Digest; + windowsAuth.ExtendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.WhenSupported); + IDictionary emptyEnv = CreateEmptyRequest(); + emptyEnv["owin.RequestScheme"] = "https"; + await windowsAuth.Invoke(emptyEnv); + FireOnSendingHeadersActions(emptyEnv); + + Assert.Equal(401, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(0, responseHeaders.Count); + Assert.Null(responseHeaders.Get("www-authenticate")); + } + + [Fact] + public async Task Digest_CbtRequiredButNotPresent_400() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = AuthTypes.Digest; + windowsAuth.ExtendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Always); + IDictionary emptyEnv = CreateEmptyRequest(); + emptyEnv["owin.RequestScheme"] = "https"; + await windowsAuth.Invoke(emptyEnv); + FireOnSendingHeadersActions(emptyEnv); + + Assert.Equal(401, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(0, responseHeaders.Count); + Assert.Null(responseHeaders.Get("www-authenticate")); + } + + [Fact(Skip = "Broken")] + public async Task Digest_ClientAuthenticates_Success() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = AuthTypes.Digest; + + using (CreateServer(windowsAuth.Invoke)) + { + HttpResponseMessage response = await SendAuthRequestAsync(Address); + Assert.Equal(DefaultStatusCode, (int)response.StatusCode); + } + } + + [Fact(Skip = "Broken")] + public async Task Digest_ClientAuthenticatesMultipleTimes_Success() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = AuthTypes.Digest; + + using (CreateServer(windowsAuth.Invoke)) + { + for (int i = 0; i < 10; i++) + { + HttpResponseMessage response = await SendAuthRequestAsync(Address); + Assert.Equal(DefaultStatusCode, (int)response.StatusCode); + } + } + } + + [Fact] + public async Task Digest_AnonmousClient_401() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = AuthTypes.Digest; + + using (CreateServer(windowsAuth.Invoke)) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(401, (int)response.StatusCode); + Assert.True(response.Headers.WwwAuthenticate.ToString().StartsWith("Digest ")); + } + } + + [Fact(Skip = "Broken")] + public async Task Digest_ClientAuthenticatesWithCbt_Success() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = AuthTypes.Digest; + windowsAuth.ExtendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Always); + + using (CreateSecureServer(windowsAuth.Invoke)) + { + HttpResponseMessage response = await SendAuthRequestAsync(SecureAddress); + Assert.Equal(DefaultStatusCode, (int)response.StatusCode); + } + } + + private IDictionary CreateEmptyRequest(string header = null, string value = null) + { + IDictionary env = new Dictionary(); + var requestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + env["owin.RequestHeaders"] = requestHeaders; + if (header != null) + { + requestHeaders[header] = new string[] { value }; + } + env["owin.ResponseHeaders"] = new Dictionary(StringComparer.OrdinalIgnoreCase); + + var onSendingHeadersActions = new List, object>>(); + env["server.OnSendingHeaders"] = new Action, object>( + (a, b) => onSendingHeadersActions.Add(new Tuple, object>(a, b))); + + env["test.OnSendingHeadersActions"] = onSendingHeadersActions; + return env; + } + + private void FireOnSendingHeadersActions(IDictionary env) + { + var onSendingHeadersActions = env.Get, object>>>("test.OnSendingHeadersActions"); + foreach (var actionPair in onSendingHeadersActions.Reverse()) + { + actionPair.Item1(actionPair.Item2); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private IDisposable CreateSecureServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "https"; + address["host"] = "localhost"; + address["port"] = "9090"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + + private async Task SendAuthRequestAsync(string uri) + { + WebRequestHandler handler = new WebRequestHandler(); + handler.UseDefaultCredentials = true; + handler.ServerCertificateValidationCallback = (a, b, c, d) => true; + using (HttpClient client = new HttpClient(handler)) + { + return await client.GetAsync(uri); + } + } + + private Task SimpleApp(IDictionary env) + { + env["owin.ResponseStatusCode"] = DefaultStatusCode; + return Task.FromResult(null); + } + } +} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs new file mode 100644 index 0000000000..572650b9b0 --- /dev/null +++ b/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs @@ -0,0 +1,261 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Authentication.ExtendedProtection; +using System.Threading.Tasks; +using Microsoft.AspNet.Server.WebListener; +using Xunit; +using Xunit.Extensions; + +namespace Microsoft.AspNet.Security.Windows.Tests +{ + using AppFunc = Func, Task>; + + public class NegotiateTests + { + private const string Address = "http://localhost:8080/"; + private const string SecureAddress = "https://localhost:9090/"; + private const int DefaultStatusCode = 201; + + [Theory] + [InlineData("Negotiate")] + [InlineData("NTLM")] + public async Task Negotiate_PartialMatch_PassedThrough(string package) + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); + IDictionary emptyEnv = CreateEmptyRequest("Authorization", package + "ion blablabla"); + await windowsAuth.Invoke(emptyEnv); + + Assert.Equal(DefaultStatusCode, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(0, responseHeaders.Count); + } + + [Theory] + [InlineData("Negotiate")] + [InlineData("NTLM")] + public async Task Negotiate_BadData_400(string package) + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); + IDictionary emptyEnv = CreateEmptyRequest("Authorization", package + " blablabla"); + await windowsAuth.Invoke(emptyEnv); + + Assert.Equal(400, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(0, responseHeaders.Count); + } + + [Theory] + [InlineData("Negotiate")] + [InlineData("NTLM")] + public async Task Negotiate_AppSets401_401WithChallenge(string package) + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp401); + windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); + IDictionary emptyEnv = CreateEmptyRequest(); + await windowsAuth.Invoke(emptyEnv); + FireOnSendingHeadersActions(emptyEnv); + + Assert.Equal(401, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(1, responseHeaders.Count); + Assert.NotNull(responseHeaders.Get("www-authenticate")); + Assert.Equal(package, responseHeaders.Get("www-authenticate")); + } + + [Theory(Skip = "Broken")] + [InlineData("Negotiate")] + [InlineData("NTLM")] + public async Task Negotiate_ClientAuthenticates_Success(string package) + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); + + using (CreateServer(windowsAuth.Invoke)) + { + HttpResponseMessage response = await SendAuthRequestAsync(Address); + Assert.Equal(DefaultStatusCode, (int)response.StatusCode); + } + } + + [Theory(Skip = "Broken")] + [InlineData("Negotiate")] + [InlineData("NTLM")] + public async Task Negotiate_ClientAuthenticatesMultipleTimes_Success(string package) + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); + + using (CreateServer(windowsAuth.Invoke)) + { + for (int i = 0; i < 10; i++) + { + HttpResponseMessage response = await SendAuthRequestAsync(Address); + Assert.Equal(DefaultStatusCode, (int)response.StatusCode); + } + } + } + + [Theory] + [InlineData("Negotiate")] + [InlineData("NTLM")] + public async Task Negotiate_AnonmousClient_401(string package) + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); + + using (CreateServer(windowsAuth.Invoke)) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(401, (int)response.StatusCode); + Assert.Equal(package, response.Headers.WwwAuthenticate.ToString()); + } + } + + [Fact(Skip = "Broken")] + public async Task UnsafeSharedNTLM_AuthenticatedClient_Success() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = AuthTypes.Ntlm; + windowsAuth.UnsafeConnectionNtlmAuthentication = true; + + using (CreateServer(windowsAuth.Invoke)) + { + WebRequestHandler handler = new WebRequestHandler(); + CredentialCache cache = new CredentialCache(); + cache.Add(new Uri(Address), "NTLM", CredentialCache.DefaultNetworkCredentials); + handler.Credentials = cache; + handler.UnsafeAuthenticatedConnectionSharing = true; + using (HttpClient client = new HttpClient(handler)) + { + HttpResponseMessage response = await client.GetAsync(Address); + Assert.Equal(DefaultStatusCode, (int)response.StatusCode); + response.EnsureSuccessStatusCode(); + + // Remove the credentials before try two just to prove they aren't used. + cache.Remove(new Uri(Address), "NTLM"); + response = await client.GetAsync(Address); + Assert.Equal(DefaultStatusCode, (int)response.StatusCode); + } + } + } + + [Theory(Skip = "Broken")] + [InlineData("Negotiate")] + [InlineData("NTLM")] + public async Task Negotiate_ClientAuthenticatesWithCbt_Success(string package) + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); + windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); + windowsAuth.ExtendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Always); + + using (CreateSecureServer(windowsAuth.Invoke)) + { + HttpResponseMessage response = await SendAuthRequestAsync(SecureAddress); + Assert.Equal(DefaultStatusCode, (int)response.StatusCode); + } + } + + private IDictionary CreateEmptyRequest(string header = null, string value = null, string connectionId = "Random") + { + IDictionary env = new Dictionary(); + var requestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + env["owin.RequestHeaders"] = requestHeaders; + if (header != null) + { + requestHeaders[header] = new string[] { value }; + } + env["owin.ResponseHeaders"] = new Dictionary(StringComparer.OrdinalIgnoreCase); + + var onSendingHeadersActions = new List, object>>(); + env["server.OnSendingHeaders"] = new Action, object>( + (a, b) => onSendingHeadersActions.Add(new Tuple, object>(a, b))); + + env["test.OnSendingHeadersActions"] = onSendingHeadersActions; + env["server.ConnectionId"] = connectionId; + return env; + } + + private void FireOnSendingHeadersActions(IDictionary env) + { + var onSendingHeadersActions = env.Get, object>>>("test.OnSendingHeadersActions"); + foreach (var actionPair in onSendingHeadersActions.Reverse()) + { + actionPair.Item1(actionPair.Item2); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private IDisposable CreateSecureServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "https"; + address["host"] = "localhost"; + address["port"] = "9090"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + + private async Task SendAuthRequestAsync(string uri) + { + WebRequestHandler handler = new WebRequestHandler(); + handler.UseDefaultCredentials = true; + handler.ServerCertificateValidationCallback = (a, b, c, d) => true; + using (HttpClient client = new HttpClient(handler)) + { + return await client.GetAsync(uri); + } + } + + private Task SimpleApp(IDictionary env) + { + env["owin.ResponseStatusCode"] = DefaultStatusCode; + return Task.FromResult(null); + } + + private Task SimpleApp401(IDictionary env) + { + env["owin.ResponseStatusCode"] = 401; + return Task.FromResult(null); + } + } +} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs new file mode 100644 index 0000000000..6ffcf2b8a8 --- /dev/null +++ b/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs @@ -0,0 +1,64 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Security.Windows.Tests +{ + public class PassThroughTests + { + private const int DefaultStatusCode = 201; + + [Fact] + public async Task PassThrough_EmptyRequest_Success() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); + IDictionary emptyEnv = CreateEmptyRequest(); + await windowsAuth.Invoke(emptyEnv); + + Assert.Equal(DefaultStatusCode, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(0, responseHeaders.Count); + } + + [Fact] + public async Task PassThrough_BasicAuth_Success() + { + WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); + IDictionary emptyEnv = CreateEmptyRequest("Authorization", "Basic blablabla"); + await windowsAuth.Invoke(emptyEnv); + + Assert.Equal(DefaultStatusCode, emptyEnv.Get("owin.ResponseStatusCode")); + var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); + Assert.Equal(0, responseHeaders.Count); + } + + private IDictionary CreateEmptyRequest(string header = null, string value = null) + { + IDictionary env = new Dictionary(); + var requestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + env["owin.RequestHeaders"] = requestHeaders; + if (header != null) + { + requestHeaders[header] = new string[] { value }; + } + env["owin.ResponseHeaders"] = new Dictionary(StringComparer.OrdinalIgnoreCase); + env["server.OnSendingHeaders"] = new Action, object>((a, b) => { }); + return env; + } + + private Task SimpleApp(IDictionary env) + { + env["owin.ResponseStatusCode"] = DefaultStatusCode; + return Task.FromResult(null); + } + } +} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..681f7d66cd --- /dev/null +++ b/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.AspNet.Security.Windows.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.AspNet.Security.Windows.Tests")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("334c99b0-a718-4cda-9ca0-d5a45c3a32b0")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("0.5")] +[assembly: AssemblyVersion("0.5")] +[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/test/Microsoft.AspNet.Security.Windows.Test/packages.config b/test/Microsoft.AspNet.Security.Windows.Test/packages.config new file mode 100644 index 0000000000..67a23e70da --- /dev/null +++ b/test/Microsoft.AspNet.Security.Windows.Test/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Security.Windows.Test/project.json b/test/Microsoft.AspNet.Security.Windows.Test/project.json new file mode 100644 index 0000000000..ecbdca9ad7 --- /dev/null +++ b/test/Microsoft.AspNet.Security.Windows.Test/project.json @@ -0,0 +1,17 @@ +{ + "version" : "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Server.WebListener" : "", + "Microsoft.AspNet.Security.Windows" : "" + }, + "configurations": { + "net45": { + "dependencies": { + "XUnit": "1.9.2", + "XUnit.Extensions": "1.9.2", + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs new file mode 100644 index 0000000000..d85855d66a --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs @@ -0,0 +1,136 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; +using Xunit.Extensions; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class AuthenticationTests + { + private const string Address = "http://localhost:8080/"; + + [Theory] + [InlineData(AuthenticationType.Kerberos)] + [InlineData(AuthenticationType.Negotiate)] + [InlineData(AuthenticationType.Ntlm)] + [InlineData(AuthenticationType.Digest)] + [InlineData(AuthenticationType.Basic)] + [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | AuthenticationType.Digest | AuthenticationType.Basic)] + public async Task AuthTypes_EnabledButNotChalleneged_PassThrough(AuthenticationType authType) + { + using (CreateServer(authType, env => + { + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + } + } + + [Theory] + [InlineData(AuthenticationType.Kerberos)] + [InlineData(AuthenticationType.Negotiate)] + [InlineData(AuthenticationType.Ntlm)] + // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented + [InlineData(AuthenticationType.Basic)] + public async Task AuthType_Specify401_ChallengesAdded(AuthenticationType authType) + { + using (CreateServer(authType, env => + { + env["owin.ResponseStatusCode"] = 401; + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + } + } + + [Fact] + public async Task MultipleAuthTypes_Specify401_ChallengesAdded() + { + // TODO: Not implemented - Digest + using (CreateServer(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationType.Basic, env => + { + env["owin.ResponseStatusCode"] = 401; + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal("Kerberos, Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + } + } + + [Theory] + [InlineData(AuthenticationType.Kerberos)] + [InlineData(AuthenticationType.Negotiate)] + [InlineData(AuthenticationType.Ntlm)] + // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationType.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationType.Basic)] + public async Task AuthTypes_Login_Success(AuthenticationType authType) + { + int requestCount = 0; + using (CreateServer(authType, env => + { + requestCount++; + object obj; + if (env.TryGetValue("server.User", out obj) && obj != null) + { + return Task.FromResult(0); + } + env["owin.ResponseStatusCode"] = 401; + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address, useDefaultCredentials: true); + response.EnsureSuccessStatusCode(); + } + } + + private IDisposable CreateServer(AuthenticationType authType, AppFunc app) + { + IDictionary properties = new Dictionary(); + OwinServerFactory.Initialize(properties); + OwinWebListener listener = (OwinWebListener)properties[typeof(OwinWebListener).FullName]; + listener.AuthenticationManager.AuthenticationTypes = authType; + + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri, bool useDefaultCredentials = false) + { + HttpClientHandler handler = new HttpClientHandler(); + handler.UseDefaultCredentials = useDefaultCredentials; + using (HttpClient client = new HttpClient(handler)) + { + return await client.GetAsync(uri); + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/DictionaryExtensions.cs b/test/Microsoft.AspNet.Server.WebListener.Test/DictionaryExtensions.cs new file mode 100644 index 0000000000..b999b1fc4f --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/DictionaryExtensions.cs @@ -0,0 +1,31 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +namespace System.Collections.Generic +{ + internal static class DictionaryExtensions + { + internal static string Get(this IDictionary dictionary, string key) + { + string[] values; + if (dictionary.TryGetValue(key, out values)) + { + return string.Join(", ", values); + } + return null; + } + + internal static T Get(this IDictionary dictionary, string key) + { + object values; + if (dictionary.TryGetValue(key, out values)) + { + return (T)values; + } + return default(T); + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs new file mode 100644 index 0000000000..98661a8380 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs @@ -0,0 +1,191 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class HttpsTests + { + private const string Address = "https://localhost:9090/"; + + [Fact] + public async Task Https_200OK_Success() + { + using (CreateServer(env => + { + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address); + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task Https_SendHelloWorld_Success() + { + using (CreateServer(env => + { + byte[] body = Encoding.UTF8.GetBytes("Hello World"); + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Content-Length"] = new string[] { body.Length.ToString() }; + return env.Get("owin.ResponseBody").WriteAsync(body, 0, body.Length); + })) + { + string response = await SendRequestAsync(Address); + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task Https_EchoHelloWorld_Success() + { + using (CreateServer(env => + { + string input = new StreamReader(env.Get("owin.RequestBody")).ReadToEnd(); + Assert.Equal("Hello World", input); + byte[] body = Encoding.UTF8.GetBytes("Hello World"); + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Content-Length"] = new string[] { body.Length.ToString() }; + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address, "Hello World"); + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task Https_ClientCertNotSent_ClientCertNotPresent() + { + X509Certificate clientCert = null; + using (CreateServer(env => + { + var loadAsync = env.Get>("ssl.LoadClientCertAsync"); + loadAsync().Wait(); + clientCert = env.Get("ssl.ClientCertificate"); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address); + Assert.Equal(string.Empty, response); + Assert.Null(clientCert); + } + } + + [Fact] + public async Task Https_ClientCertRequested_ClientCertPresent() + { + X509Certificate clientCert = null; + using (CreateServer(env => + { + var loadAsync = env.Get>("ssl.LoadClientCertAsync"); + loadAsync().Wait(); + clientCert = env.Get("ssl.ClientCertificate"); + return Task.FromResult(0); + })) + { + X509Certificate2 cert = FindClientCert(); + Assert.NotNull(cert); + string response = await SendRequestAsync(Address, cert); + Assert.Equal(string.Empty, response); + Assert.NotNull(clientCert); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "https"; + address["host"] = "localhost"; + address["port"] = "9090"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri, + X509Certificate cert = null) + { + WebRequestHandler handler = new WebRequestHandler(); + handler.ServerCertificateValidationCallback = (a, b, c, d) => true; + if (cert != null) + { + handler.ClientCertificates.Add(cert); + } + using (HttpClient client = new HttpClient(handler)) + { + return await client.GetStringAsync(uri); + } + } + + private async Task SendRequestAsync(string uri, string upload) + { + WebRequestHandler handler = new WebRequestHandler(); + handler.ServerCertificateValidationCallback = (a, b, c, d) => true; + using (HttpClient client = new HttpClient(handler)) + { + HttpResponseMessage response = await client.PostAsync(uri, new StringContent(upload)); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + } + + private X509Certificate2 FindClientCert() + { + var store = new X509Store(); + store.Open(OpenFlags.ReadOnly); + + foreach (var cert in store.Certificates) + { + bool isClientAuth = false; + bool isSmartCard = false; + foreach (var extension in cert.Extensions) + { + var eku = extension as X509EnhancedKeyUsageExtension; + if (eku != null) + { + foreach (var oid in eku.EnhancedKeyUsages) + { + if (oid.FriendlyName == "Client Authentication") + { + isClientAuth = true; + } + else if (oid.FriendlyName == "Smart Card Logon") + { + isSmartCard = true; + break; + } + } + } + } + + if (isClientAuth && !isSmartCard) + { + return cert; + } + } + return null; + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs new file mode 100644 index 0000000000..07c8610feb --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs @@ -0,0 +1,324 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; +using Xunit.Extensions; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + using OpaqueUpgrade = Action, Func, Task>>; + + public class OpaqueUpgradeTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task OpaqueUpgrade_SupportKeys_Present() + { + using (CreateServer(env => + { + try + { + IDictionary capabilities = env.Get>("server.Capabilities"); + Assert.NotNull(capabilities); + + Assert.Equal("1.0", capabilities.Get("opaque.Version")); + + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + Assert.NotNull(opaqueUpgrade); + } + catch (Exception ex) + { + byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(0, response.Content.Headers.ContentLength); + Assert.Equal(string.Empty, response.Content.ReadAsStringAsync().Result); + } + } + + [Fact] + public async Task OpaqueUpgrade_NullCallback_Throws() + { + using (CreateServer(env => + { + try + { + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + opaqueUpgrade(new Dictionary(), null); + } + catch (Exception ex) + { + byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Contains("callback", response.Content.ReadAsStringAsync().Result); + } + } + + [Fact] + public async Task OpaqueUpgrade_AfterHeadersSent_Throws() + { + bool? upgradeThrew = null; + using (CreateServer(env => + { + byte[] body = Encoding.UTF8.GetBytes("Hello World"); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + try + { + opaqueUpgrade(null, _ => Task.FromResult(0)); + upgradeThrew = false; + } + catch (InvalidOperationException) + { + upgradeThrew = true; + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.True(upgradeThrew.Value); + } + } + + [Fact] + public async Task OpaqueUpgrade_GetUpgrade_Success() + { + ManualResetEvent waitHandle = new ManualResetEvent(false); + bool? callbackInvoked = null; + using (CreateServer(env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Upgrade"] = new string[] { "websocket" }; // Win8.1 blocks anything but WebSockets + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + opaqueUpgrade(null, opqEnv => + { + callbackInvoked = true; + waitHandle.Set(); + return Task.FromResult(0); + }); + return Task.FromResult(0); + })) + { + using (Stream stream = await SendOpaqueRequestAsync("GET", Address)) + { + Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); + Assert.True(callbackInvoked.HasValue, "CallbackInvoked not set"); + Assert.True(callbackInvoked.Value, "Callback not invoked"); + } + } + } + + [Theory] + // See HTTP_VERB for known verbs + [InlineData("UNKNOWN", null)] + [InlineData("INVALID", null)] + [InlineData("OPTIONS", null)] + [InlineData("GET", null)] + [InlineData("HEAD", null)] + [InlineData("DELETE", null)] + [InlineData("TRACE", null)] + [InlineData("CONNECT", null)] + [InlineData("TRACK", null)] + [InlineData("MOVE", null)] + [InlineData("COPY", null)] + [InlineData("PROPFIND", null)] + [InlineData("PROPPATCH", null)] + [InlineData("MKCOL", null)] + [InlineData("LOCK", null)] + [InlineData("UNLOCK", null)] + [InlineData("SEARCH", null)] + [InlineData("CUSTOMVERB", null)] + [InlineData("PATCH", null)] + [InlineData("POST", "Content-Length: 0")] + [InlineData("PUT", "Content-Length: 0")] + public async Task OpaqueUpgrade_VariousMethodsUpgradeSendAndReceive_Success(string method, string extraHeader) + { + using (CreateServer(env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Upgrade"] = new string[] { "WebSocket" }; // Win8.1 blocks anything but WebSockets + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + opaqueUpgrade(null, async opqEnv => + { + Stream opaqueStream = opqEnv.Get("opaque.Stream"); + + byte[] buffer = new byte[100]; + int read = await opaqueStream.ReadAsync(buffer, 0, buffer.Length); + + await opaqueStream.WriteAsync(buffer, 0, read); + }); + return Task.FromResult(0); + })) + { + using (Stream stream = await SendOpaqueRequestAsync(method, Address, extraHeader)) + { + byte[] data = new byte[100]; + stream.WriteAsync(data, 0, 49).Wait(); + int read = stream.ReadAsync(data, 0, data.Length).Result; + Assert.Equal(49, read); + } + } + } + + [Theory] + // Http.Sys returns a 411 Length Required if PUT or POST does not specify content-length or chunked. + [InlineData("POST", "Content-Length: 10")] + [InlineData("POST", "Transfer-Encoding: chunked")] + [InlineData("PUT", "Content-Length: 10")] + [InlineData("PUT", "Transfer-Encoding: chunked")] + [InlineData("CUSTOMVERB", "Content-Length: 10")] + [InlineData("CUSTOMVERB", "Transfer-Encoding: chunked")] + public void OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) + { + OpaqueUpgrade opaqueUpgrade = null; + using (CreateServer(env => + { + opaqueUpgrade = env.Get("opaque.Upgrade"); + if (opaqueUpgrade == null) + { + throw new NotImplementedException(); + } + opaqueUpgrade(null, opqEnv => Task.FromResult(0)); + return Task.FromResult(0); + })) + { + Assert.Throws(() => + { + try + { + return SendOpaqueRequestAsync(method, Address, extraHeader).Result; + } + catch (AggregateException ag) + { + throw ag.GetBaseException(); + } + }); + Assert.Null(opaqueUpgrade); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + OwinServerFactory.Initialize(properties); + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + + // Returns a bidirectional opaque stream or throws if the upgrade fails + private async Task SendOpaqueRequestAsync(string method, string address, string extraHeader = null) + { + // Connect with a socket + Uri uri = new Uri(address); + TcpClient client = new TcpClient(); + try + { + await client.ConnectAsync(uri.Host, uri.Port); + NetworkStream stream = client.GetStream(); + + // Send an HTTP GET request + byte[] requestBytes = BuildGetRequest(method, uri, extraHeader); + await stream.WriteAsync(requestBytes, 0, requestBytes.Length); + + // Read the response headers, fail if it's not a 101 + await ParseResponseAsync(stream); + + // Return the opaque network stream + return stream; + } + catch (Exception) + { + client.Close(); + throw; + } + } + + private byte[] BuildGetRequest(string method, Uri uri, string extraHeader) + { + StringBuilder builder = new StringBuilder(); + builder.Append(method); + builder.Append(" "); + builder.Append(uri.PathAndQuery); + builder.Append(" HTTP/1.1"); + builder.AppendLine(); + + builder.Append("Host: "); + builder.Append(uri.Host); + builder.Append(':'); + builder.Append(uri.Port); + builder.AppendLine(); + + if (!string.IsNullOrEmpty(extraHeader)) + { + builder.AppendLine(extraHeader); + } + + builder.AppendLine(); + return Encoding.ASCII.GetBytes(builder.ToString()); + } + + // Read the response headers, fail if it's not a 101 + private async Task ParseResponseAsync(NetworkStream stream) + { + StreamReader reader = new StreamReader(stream); + string statusLine = await reader.ReadLineAsync(); + string[] parts = statusLine.Split(' '); + if (int.Parse(parts[1]) != 101) + { + throw new InvalidOperationException("The response status code was incorrect: " + statusLine); + } + + // Scan to the end of the headers + while (!string.IsNullOrEmpty(reader.ReadLine())) + { + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..486c5d20cd --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.AspNet.Server.WebListener.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.AspNet.Server.WebListener.Tests")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a265fcd6-3542-4f59-a1dd-ad423d40ddde")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("0.5")] +[assembly: AssemblyVersion("0.5")] +[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs new file mode 100644 index 0000000000..3687766ca1 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs @@ -0,0 +1,176 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class RequestBodyTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task RequestBody_ReadSync_Success() + { + using (CreateServer(env => + { + byte[] input = new byte[100]; + int read = env.Get("owin.RequestBody").Read(input, 0, input.Length); + + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Content-Length"] = new string[] { read.ToString() }; + env.Get("owin.ResponseBody").Write(input, 0, read); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address, "Hello World"); + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task RequestBody_ReadAync_Success() + { + using (CreateServer(async env => + { + byte[] input = new byte[100]; + int read = await env.Get("owin.RequestBody").ReadAsync(input, 0, input.Length); + + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Content-Length"] = new string[] { read.ToString() }; + await env.Get("owin.ResponseBody").WriteAsync(input, 0, read); + })) + { + string response = await SendRequestAsync(Address, "Hello World"); + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task RequestBody_ReadBeginEnd_Success() + { + using (CreateServer(env => + { + Stream requestStream = env.Get("owin.RequestBody"); + byte[] input = new byte[100]; + int read = requestStream.EndRead(requestStream.BeginRead(input, 0, input.Length, null, null)); + + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Content-Length"] = new string[] { read.ToString() }; + Stream responseStream = env.Get("owin.ResponseBody"); + responseStream.EndWrite(responseStream.BeginWrite(input, 0, read, null, null)); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address, "Hello World"); + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task RequestBody_ReadSyncPartialBody_Success() + { + StaggardContent content = new StaggardContent(); + using (CreateServer(env => + { + byte[] input = new byte[10]; + int read = env.Get("owin.RequestBody").Read(input, 0, input.Length); + Assert.Equal(5, read); + content.Block.Release(); + read = env.Get("owin.RequestBody").Read(input, 0, input.Length); + Assert.Equal(5, read); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address, content); + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestBody_ReadAsyncPartialBody_Success() + { + StaggardContent content = new StaggardContent(); + using (CreateServer(async env => + { + byte[] input = new byte[10]; + int read = await env.Get("owin.RequestBody").ReadAsync(input, 0, input.Length); + Assert.Equal(5, read); + content.Block.Release(); + read = await env.Get("owin.RequestBody").ReadAsync(input, 0, input.Length); + Assert.Equal(5, read); + })) + { + string response = await SendRequestAsync(Address, content); + Assert.Equal(string.Empty, response); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private Task SendRequestAsync(string uri, string upload) + { + return SendRequestAsync(uri, new StringContent(upload)); + } + + private async Task SendRequestAsync(string uri, HttpContent content) + { + using (HttpClient client = new HttpClient()) + { + HttpResponseMessage response = await client.PostAsync(uri, content); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + } + + private class StaggardContent : HttpContent + { + public StaggardContent() + { + Block = new SemaphoreSlim(0, 1); + } + + public SemaphoreSlim Block { get; private set; } + + protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) + { + await stream.WriteAsync(new byte[5], 0, 5); + await Block.WaitAsync(); + await stream.WriteAsync(new byte[5], 0, 5); + } + + protected override bool TryComputeLength(out long length) + { + length = 10; + return true; + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs new file mode 100644 index 0000000000..a322ea06d0 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs @@ -0,0 +1,120 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class RequestHeaderTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task RequestHeaders_ClientSendsDefaultHeaders_Success() + { + using (CreateServer(env => + { + var requestHeaders = env.Get>("owin.RequestHeaders"); + // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. + // Assert.Equal(2, requestHeaders.Count); + // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); + Assert.Equal("localhost:8080", requestHeaders.Get("Host")); + Assert.Equal(null, requestHeaders.Get("Accept")); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address); + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestHeaders_ClientSendsCustomHeaders_Success() + { + using (CreateServer(env => + { + var requestHeaders = env.Get>("owin.RequestHeaders"); + Assert.Equal(4, requestHeaders.Count); + Assert.Equal("localhost:8080", requestHeaders.Get("Host")); + Assert.Equal("close", requestHeaders.Get("Connection")); + Assert.Equal(1, requestHeaders["Custom-Header"].Length); + // Apparently Http.Sys squashes request headers together. + Assert.Equal("custom1, and custom2, custom3", requestHeaders.Get("Custom-Header")); + Assert.Equal(1, requestHeaders["Spacer-Header"].Length); + Assert.Equal("spacervalue, spacervalue", requestHeaders.Get("Spacer-Header")); + return Task.FromResult(0); + })) + { + string[] customValues = new string[] { "custom1, and custom2", "custom3" }; + + await SendRequestAsync("localhost", 8080, "Custom-Header", customValues); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetStringAsync(uri); + } + } + + private async Task SendRequestAsync(string host, int port, string customHeader, string[] customValues) + { + StringBuilder builder = new StringBuilder(); + builder.AppendLine("GET / HTTP/1.1"); + builder.AppendLine("Connection: close"); + builder.Append("HOST: "); + builder.Append(host); + builder.Append(':'); + builder.AppendLine(port.ToString()); + foreach (string value in customValues) + { + builder.Append(customHeader); + builder.Append(": "); + builder.AppendLine(value); + builder.AppendLine("Spacer-Header: spacervalue"); + } + builder.AppendLine(); + + byte[] request = Encoding.ASCII.GetBytes(builder.ToString()); + + Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + socket.Connect(host, port); + + socket.Send(request); + + byte[] response = new byte[1024 * 5]; + await Task.Run(() => socket.Receive(response)); + socket.Close(); + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs new file mode 100644 index 0000000000..a99bdafa86 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs @@ -0,0 +1,185 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; +using Xunit.Extensions; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class RequestTests + { + private const string Address = "http://localhost:8080"; + + [Fact] + public async Task Request_SimpleGet_Success() + { + using (CreateServer(env => + { + try + { + // General keys + Assert.Equal("1.0", env.Get("owin.Version")); + Assert.True(env.Get("owin.CallCancelled").CanBeCanceled); + + // Request Keys + Assert.Equal("GET", env.Get("owin.RequestMethod")); + Assert.Equal(Stream.Null, env.Get("owin.RequestBody")); + Assert.NotNull(env.Get>("owin.RequestHeaders")); + Assert.Equal("http", env.Get("owin.RequestScheme")); + Assert.Equal("/basepath", env.Get("owin.RequestPathBase")); + Assert.Equal("/SomePath", env.Get("owin.RequestPath")); + Assert.Equal("SomeQuery", env.Get("owin.RequestQueryString")); + Assert.Equal("HTTP/1.1", env.Get("owin.RequestProtocol")); + + // Server Keys + Assert.NotNull(env.Get>("server.Capabilities")); + Assert.Equal("::1", env.Get("server.RemoteIpAddress")); + Assert.NotNull(env.Get("server.RemotePort")); + Assert.Equal("::1", env.Get("server.LocalIpAddress")); + Assert.Equal("8080", env.Get("server.LocalPort")); + Assert.True(env.Get("server.IsLocal")); + + // Note: Response keys are validated in the ResponseTests + } + catch (Exception ex) + { + byte[] body = Encoding.ASCII.GetBytes(ex.ToString()); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + } + return Task.FromResult(0); + }, "http", "localhost", "8080", "/basepath")) + { + string response = await SendRequestAsync(Address + "/basepath/SomePath?SomeQuery"); + Assert.Equal(string.Empty, response); + } + } + + [Theory] + [InlineData("http", "localhost", "8080", "/", "http://localhost:8080/", "", "/")] + [InlineData("http", "localhost", "8080", "/basepath/", "http://localhost:8080/basepath", "/basepath", "")] + [InlineData("http", "localhost", "8080", "/basepath/", "http://localhost:8080/basepath/", "/basepath", "/")] + [InlineData("http", "localhost", "8080", "/basepath/", "http://localhost:8080/basepath/subpath", "/basepath", "/subpath")] + [InlineData("http", "localhost", "8080", "/base path/", "http://localhost:8080/base%20path/sub path", "/base path", "/sub path")] + [InlineData("http", "localhost", "8080", "/base葉path/", "http://localhost:8080/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] + public async Task Request_PathSplitting(string scheme, string host, string port, string pathBase, string requestUri, + string expectedPathBase, string expectedPath) + { + using (CreateServer(env => + { + try + { + Uri uri = new Uri(requestUri); + string expectedQuery = uri.Query.Length > 0 ? uri.Query.Substring(1) : string.Empty; + // Request Keys + Assert.Equal(scheme, env.Get("owin.RequestScheme")); + Assert.Equal(expectedPath, env.Get("owin.RequestPath")); + Assert.Equal(expectedPathBase, env.Get("owin.RequestPathBase")); + Assert.Equal(expectedQuery, env.Get("owin.RequestQueryString")); + Assert.Equal(port, env.Get("server.LocalPort")); + } + catch (Exception ex) + { + byte[] body = Encoding.ASCII.GetBytes(ex.ToString()); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + } + return Task.FromResult(0); + }, scheme, host, port, pathBase)) + { + string response = await SendRequestAsync(requestUri); + Assert.Equal(string.Empty, response); + } + } + + [Theory] + // The test server defines these prefixes: "/", "/11", "/2/3", "/2", "/11/2" + [InlineData("/", "", "/")] + [InlineData("/random", "", "/random")] + [InlineData("/11", "/11", "")] + [InlineData("/11/", "/11", "/")] + [InlineData("/11/random", "/11", "/random")] + [InlineData("/2", "/2", "")] + [InlineData("/2/", "/2", "/")] + [InlineData("/2/random", "/2", "/random")] + [InlineData("/2/3", "/2/3", "")] + [InlineData("/2/3/", "/2/3", "/")] + [InlineData("/2/3/random", "/2/3", "/random")] + public async Task Request_MultiplePrefixes(string requestUri, string expectedPathBase, string expectedPath) + { + using (CreateServer(env => + { + try + { + Assert.Equal(expectedPath, env.Get("owin.RequestPath")); + Assert.Equal(expectedPathBase, env.Get("owin.RequestPathBase")); + } + catch (Exception ex) + { + byte[] body = Encoding.ASCII.GetBytes(ex.ToString()); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + } + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address + requestUri); + Assert.Equal(string.Empty, response); + } + } + + private IDisposable CreateServer(AppFunc app, string scheme, string host, string port, string path) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = scheme; + address["host"] = host; + address["port"] = port; + address["path"] = path; + + return OwinServerFactory.Create(app, properties); + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) + { + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = path; + } + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetStringAsync(uri); + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs new file mode 100644 index 0000000000..bc95cb305f --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs @@ -0,0 +1,213 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class ResponseBodyTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() + { + using (CreateServer(env => + { + env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); + return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_WriteChunked_Chunked() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["transfeR-Encoding"] = new string[] { " CHunked " }; + Stream stream = env.Get("owin.ResponseBody"); + stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); + stream.Write(new byte[10], 0, 10); + return stream.WriteAsync(new byte[10], 0, 10); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_WriteContentLength_PassedThrough() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 30 " }; + Stream stream = env.Get("owin.ResponseBody"); + stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); + stream.Write(new byte[10], 0, 10); + return stream.WriteAsync(new byte[10], 0, 10); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal("30", contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_Http10WriteNoHeaders_DefaultsConnectionClose() + { + using (CreateServer(env => + { + env["owin.ResponseProtocol"] = "HTTP/1.0"; + env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); + return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); // Http.Sys won't transmit 1.0 + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public void ResponseBody_WriteContentLengthNoneWritten_Throws() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 20 " }; + return Task.FromResult(0); + })) + { + Assert.Throws(() => SendRequestAsync(Address).Result); + } + } + + [Fact] + public void ResponseBody_WriteContentLengthNotEnoughWritten_Throws() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 20 " }; + env.Get("owin.ResponseBody").Write(new byte[5], 0, 5); + return Task.FromResult(0); + })) + { + Assert.Throws(() => SendRequestAsync(Address).Result); + } + } + + [Fact] + public void ResponseBody_WriteContentLengthTooMuchWritten_Throws() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 10 " }; + env.Get("owin.ResponseBody").Write(new byte[5], 0, 5); + env.Get("owin.ResponseBody").Write(new byte[6], 0, 6); + return Task.FromResult(0); + })) + { + Assert.Throws(() => SendRequestAsync(Address).Result); + } + } + + [Fact] + public async Task ResponseBody_WriteContentLengthExtraWritten_Throws() + { + ManualResetEvent waitHandle = new ManualResetEvent(false); + bool? appThrew = null; + using (CreateServer(env => + { + try + { + env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 10 " }; + env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); + env.Get("owin.ResponseBody").Write(new byte[9], 0, 9); + appThrew = false; + } + catch (Exception) + { + appThrew = true; + } + waitHandle.Set(); + return Task.FromResult(0); + })) + { + // The full response is received. + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal("10", contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + + Assert.True(waitHandle.WaitOne(100)); + Assert.True(appThrew.HasValue, "appThrew.HasValue"); + Assert.True(appThrew.Value, "appThrew.Value"); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs new file mode 100644 index 0000000000..56b3bb48f4 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs @@ -0,0 +1,243 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class ResponseHeaderTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task ResponseHeaders_ServerSendsDefaultHeaders_Success() + { + using (CreateServer(env => + { + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.Equal(2, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.Equal(1, response.Content.Headers.Count()); + Assert.Equal(0, response.Content.Headers.ContentLength); + } + } + + [Fact] + public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() + { + using (CreateServer(env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Custom-Header1"] = new string[] { "custom1, and custom2", "custom3" }; + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.Equal(3, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); + Assert.Equal(1, response.Content.Headers.Count()); + Assert.Equal(0, response.Content.Headers.ContentLength); + } + } + + [Fact] + public async Task ResponseHeaders_ServerSendsConnectionClose_Closed() + { + using (CreateServer(env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Connection"] = new string[] { "Close" }; + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + + [Fact] + public async Task ResponseHeaders_SendsHttp10_Gets11Close() + { + using (CreateServer(env => + { + env["owin.ResponseProtocol"] = "HTTP/1.0"; + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + + [Fact] + public async Task ResponseHeaders_SendsHttp10WithBody_Gets11Close() + { + using (CreateServer(env => + { + env["owin.ResponseProtocol"] = "HTTP/1.0"; + return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.False(response.Content.Headers.Contains("Content-Length")); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + + [Fact] + public async Task ResponseHeaders_HTTP10Request_Gets11Close() + { + using (CreateServer(env => + { + return Task.FromResult(0); + })) + { + using (HttpClient client = new HttpClient()) + { + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Address); + request.Version = new Version(1, 0); + HttpResponseMessage response = await client.SendAsync(request); + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + } + + [Fact] + public async Task ResponseHeaders_HTTP10Request_RemovesChunkedHeader() + { + using (CreateServer(env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Transfer-Encoding"] = new string[] { "chunked" }; + return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); + })) + { + using (HttpClient client = new HttpClient()) + { + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Address); + request.Version = new Version(1, 0); + HttpResponseMessage response = await client.SendAsync(request); + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.False(response.Content.Headers.Contains("Content-Length")); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + } + + [Fact] + public async Task Headers_FlushSendsHeaders_Success() + { + using (CreateServer( + env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); + responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); + var body = env.Get("owin.ResponseBody"); + body.Flush(); + env["owin.ResponseStatusCode"] = 404; // Ignored + responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.Equal(5, response.Headers.Count()); // Date, Server, Chunked + + Assert.Equal(2, response.Headers.GetValues("Custom1").Count()); + Assert.Equal("value1a", response.Headers.GetValues("Custom1").First()); + Assert.Equal("value1b", response.Headers.GetValues("Custom1").Skip(1).First()); + Assert.Equal(1, response.Headers.GetValues("Custom2").Count()); + Assert.Equal("value2a, value2b", response.Headers.GetValues("Custom2").First()); + } + } + + [Fact] + public async Task Headers_FlushAsyncSendsHeaders_Success() + { + using (CreateServer( + async env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); + responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); + var body = env.Get("owin.ResponseBody"); + await body.FlushAsync(); + env["owin.ResponseStatusCode"] = 404; // Ignored + responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.Equal(5, response.Headers.Count()); // Date, Server, Chunked + + Assert.Equal(2, response.Headers.GetValues("Custom1").Count()); + Assert.Equal("value1a", response.Headers.GetValues("Custom1").First()); + Assert.Equal("value1b", response.Headers.GetValues("Custom1").Skip(1).First()); + Assert.Equal(1, response.Headers.GetValues("Custom2").Count()); + Assert.Equal("value2a, value2b", response.Headers.GetValues("Custom2").First()); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs new file mode 100644 index 0000000000..d176dc2a1a --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs @@ -0,0 +1,327 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + using SendFileFunc = Func; + + public class ResponseSendFileTests + { + private const string Address = "http://localhost:8080/"; + private static readonly string AbsoluteFilePath = Environment.CurrentDirectory + "\\Microsoft.AspNet.Server.WebListener.dll"; + private static readonly string RelativeFilePath = "Microsoft.AspNet.Server.WebListener.dll"; + private static readonly long FileLength = new FileInfo(AbsoluteFilePath).Length; + + [Fact] + public async Task ResponseSendFile_SupportKeys_Present() + { + using (CreateServer(env => + { + try + { + IDictionary capabilities = env.Get>("server.Capabilities"); + Assert.NotNull(capabilities); + + Assert.Equal("1.0", capabilities.Get("sendfile.Version")); + + IDictionary support = capabilities.Get>("sendfile.Support"); + Assert.NotNull(support); + + Assert.Equal("Overlapped", support.Get("sendfile.Concurrency")); + + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + Assert.NotNull(sendFileAsync); + } + catch (Exception ex) + { + byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable ignored; + Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(0, response.Content.Headers.ContentLength); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task ResponseSendFile_MissingFile_Throws() + { + ManualResetEvent waitHandle = new ManualResetEvent(false); + bool? appThrew = null; + using (CreateServer(env => + { + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + try + { + sendFileAsync(string.Empty, 0, null, CancellationToken.None).Wait(); + appThrew = false; + } + catch (Exception) + { + appThrew = true; + throw; + } + finally + { + waitHandle.Set(); + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + Assert.True(waitHandle.WaitOne(100)); + Assert.True(appThrew.HasValue, "appThrew.HasValue"); + Assert.True(appThrew.Value, "appThrew.Value"); + } + } + + [Fact] + public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() + { + using (CreateServer(env => + { + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(FileLength, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_RelativeFile_Success() + { + using (CreateServer(env => + { + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(FileLength, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_Chunked_Chunked() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Transfer-EncodinG"] = new string[] { "CHUNKED" }; + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(FileLength, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_MultipleChunks_Chunked() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Transfer-EncodinG"] = new string[] { "CHUNKED" }; + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None).Wait(); + return sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_ChunkedHalfOfFile_Chunked() + { + using (CreateServer(env => + { + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(FileLength / 2, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_ChunkedOffsetOutOfRange_Throws() + { + using (CreateServer(env => + { + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(500, (int)response.StatusCode); + } + } + + [Fact] + public async Task ResponseSendFile_ChunkedCountOutOfRange_Throws() + { + using (CreateServer(env => + { + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(500, (int)response.StatusCode); + } + } + + [Fact] + public async Task ResponseSendFile_ChunkedCount0_Chunked() + { + using (CreateServer(env => + { + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_ContentLength_PassedThrough() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { FileLength.ToString() }; + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal(FileLength.ToString(), contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(FileLength, response.Content.ReadAsByteArrayAsync().Result.Length); + } + } + + [Fact] + public async Task ResponseSendFile_ContentLengthSpecific_PassedThrough() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { "10" }; + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal("10", contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(10, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_ContentLength0_PassedThrough() + { + using (CreateServer(env => + { + env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { "0" }; + SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + return sendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal("0", contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IList> addresses = new List>(); + IDictionary properties = new Dictionary(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + OwinServerFactory.Initialize(properties); + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs new file mode 100644 index 0000000000..537ad8c6c9 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs @@ -0,0 +1,142 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class ResponseTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task Response_ServerSendsDefaultResponse_ServerProvidesStatusCodeAndReasonPhrase() + { + using (CreateServer(env => + { + Assert.Equal(200, env["owin.ResponseStatusCode"]); + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("OK", response.ReasonPhrase); + Assert.Equal(new Version(1, 1), response.Version); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task Response_ServerSendsSpecificStatus_ServerProvidesReasonPhrase() + { + using (CreateServer(env => + { + env["owin.ResponseStatusCode"] = 201; + env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(201, (int)response.StatusCode); + Assert.Equal("Created", response.ReasonPhrase); + Assert.Equal(new Version(1, 1), response.Version); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task Response_ServerSendsSpecificStatusAndReasonPhrase_PassedThrough() + { + using (CreateServer(env => + { + env["owin.ResponseStatusCode"] = 201; + env["owin.ResponseReasonPhrase"] = "CustomReasonPhrase"; + env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(201, (int)response.StatusCode); + Assert.Equal("CustomReasonPhrase", response.ReasonPhrase); + Assert.Equal(new Version(1, 1), response.Version); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task Response_ServerSendsCustomStatus_NoReasonPhrase() + { + using (CreateServer(env => + { + env["owin.ResponseStatusCode"] = 901; + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(901, (int)response.StatusCode); + Assert.Equal(string.Empty, response.ReasonPhrase); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public void Response_100_Throws() + { + using (CreateServer(env => + { + env["owin.ResponseStatusCode"] = 100; + return Task.FromResult(0); + })) + { + Assert.Throws(() => SendRequestAsync(Address).Result); + } + } + + [Fact] + public void Response_0_Throws() + { + using (CreateServer(env => + { + env["owin.ResponseStatusCode"] = 0; + return Task.FromResult(0); + })) + { + Assert.Throws(() => SendRequestAsync(Address).Result); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs new file mode 100644 index 0000000000..84f76d9a52 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs @@ -0,0 +1,287 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.Tests +{ + using AppFunc = Func, Task>; + + public class ServerTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task Server_200OK_Success() + { + using (CreateServer(env => + { + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address); + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task Server_SendHelloWorld_Success() + { + using (CreateServer(env => + { + byte[] body = Encoding.UTF8.GetBytes("Hello World"); + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Content-Length"] = new string[] { body.Length.ToString() }; + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address); + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task Server_EchoHelloWorld_Success() + { + using (CreateServer(env => + { + string input = new StreamReader(env.Get("owin.RequestBody")).ReadToEnd(); + Assert.Equal("Hello World", input); + byte[] body = Encoding.UTF8.GetBytes("Hello World"); + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Content-Length"] = new string[] { body.Length.ToString() }; + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address, "Hello World"); + Assert.Equal("Hello World", response); + } + } + + [Fact] + public void Server_AppException_ClientReset() + { + using (CreateServer(env => + { + throw new InvalidOperationException(); + })) + { + Task requestTask = SendRequestAsync(Address); + Assert.Throws(() => requestTask.Result); + + // Do it again to make sure the server didn't crash + requestTask = SendRequestAsync(Address); + Assert.Throws(() => requestTask.Result); + } + } + + [Fact] + public void Server_MultipleOutstandingSyncRequests_Success() + { + int requestLimit = 10; + int requestCount = 0; + TaskCompletionSource tcs = new TaskCompletionSource(); + + using (CreateServer(env => + { + if (Interlocked.Increment(ref requestCount) == requestLimit) + { + tcs.TrySetResult(null); + } + else + { + tcs.Task.Wait(); + } + + return Task.FromResult(0); + })) + { + List requestTasks = new List(); + for (int i = 0; i < requestLimit; i++) + { + Task requestTask = SendRequestAsync(Address); + requestTasks.Add(requestTask); + } + + bool success = Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(5)); + if (!success) + { + Console.WriteLine(); + } + Assert.True(success, "Timed out"); + } + } + + [Fact] + public void Server_MultipleOutstandingAsyncRequests_Success() + { + int requestLimit = 10; + int requestCount = 0; + TaskCompletionSource tcs = new TaskCompletionSource(); + + using (CreateServer(async env => + { + if (Interlocked.Increment(ref requestCount) == requestLimit) + { + tcs.TrySetResult(null); + } + else + { + await tcs.Task; + } + })) + { + List requestTasks = new List(); + for (int i = 0; i < requestLimit; i++) + { + Task requestTask = SendRequestAsync(Address); + requestTasks.Add(requestTask); + } + Assert.True(Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(2)), "Timed out"); + } + } + + [Fact] + public async Task Server_ClientDisconnects_CallCancelled() + { + TimeSpan interval = TimeSpan.FromSeconds(1); + ManualResetEvent received = new ManualResetEvent(false); + ManualResetEvent aborted = new ManualResetEvent(false); + ManualResetEvent canceled = new ManualResetEvent(false); + + using (CreateServer(env => + { + CancellationToken ct = env.Get("owin.CallCancelled"); + Assert.True(ct.CanBeCanceled, "CanBeCanceled"); + Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); + ct.Register(() => canceled.Set()); + received.Set(); + Assert.True(aborted.WaitOne(interval), "Aborted"); + Assert.True(ct.WaitHandle.WaitOne(interval), "CT Wait"); + Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); + return Task.FromResult(0); + })) + { + // Note: System.Net.Sockets does not RST the connection by default, it just FINs. + // Http.Sys's disconnect notice requires a RST. + using (Socket socket = await SendHungRequestAsync("GET", Address)) + { + Assert.True(received.WaitOne(interval), "Receive Timeout"); + socket.Close(0); // Force a RST + aborted.Set(); + } + Assert.True(canceled.WaitOne(interval), "canceled"); + } + } + + [Fact] + public async Task Server_SetQueueLimit_Success() + { + using (CreateServer(env => + { + // There's no good way to validate this in code. Just execute it to make sure it doesn't crash. + // Run "netsh http show servicestate" to see the current value + var listener = env.Get("Microsoft.AspNet.Server.WebListener.OwinWebListener"); + listener.SetRequestQueueLimit(1001); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address); + Assert.Equal(string.Empty, response); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + ServicePointManager.DefaultConnectionLimit = 100; + using (HttpClient client = new HttpClient()) + { + return await client.GetStringAsync(uri); + } + } + + private async Task SendRequestAsync(string uri, string upload) + { + using (HttpClient client = new HttpClient()) + { + HttpResponseMessage response = await client.PostAsync(uri, new StringContent(upload)); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + } + + private async Task SendHungRequestAsync(string method, string address) + { + // Connect with a socket + Uri uri = new Uri(address); + TcpClient client = new TcpClient(); + try + { + await client.ConnectAsync(uri.Host, uri.Port); + NetworkStream stream = client.GetStream(); + + // Send an HTTP GET request + byte[] requestBytes = BuildGetRequest(method, uri); + await stream.WriteAsync(requestBytes, 0, requestBytes.Length); + + // Return the opaque network stream + return client.Client; + } + catch (Exception) + { + client.Close(); + throw; + } + } + + private byte[] BuildGetRequest(string method, Uri uri) + { + StringBuilder builder = new StringBuilder(); + builder.Append(method); + builder.Append(" "); + builder.Append(uri.PathAndQuery); + builder.Append(" HTTP/1.1"); + builder.AppendLine(); + + builder.Append("Host: "); + builder.Append(uri.Host); + builder.Append(':'); + builder.Append(uri.Port); + builder.AppendLine(); + + builder.AppendLine(); + return Encoding.ASCII.GetBytes(builder.ToString()); + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/project.json b/test/Microsoft.AspNet.Server.WebListener.Test/project.json new file mode 100644 index 0000000000..b11449f836 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/project.json @@ -0,0 +1,16 @@ +{ + "version" : "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Server.WebListener" : "" + }, + "configurations": { + "net45": { + "dependencies": { + "XUnit": "1.9.2", + "XUnit.Extensions": "1.9.2", + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" + } + } + } +} From 5300428a3335fbf7dc1de4a2f909129818bce25e Mon Sep 17 00:00:00 2001 From: David Fowler Date: Mon, 10 Feb 2014 22:42:16 -0800 Subject: [PATCH 002/597] Updated build template --- .gitignore | 2 ++ NuGet.Config | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2554a1fc23..8bc217058d 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ nuget.exe *.userprefs *DS_Store *.ncrunchsolution +*.*sdf +*.ipch \ No newline at end of file diff --git a/NuGet.Config b/NuGet.Config index ab583b0ff7..a059188b09 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@  - + From 5cece8b4af4f85cf692c4146263585a3bc73655c Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 12 Feb 2014 14:27:20 -0800 Subject: [PATCH 003/597] Rename solution file. --- KatanaInternal.sln => WebListener.sln | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename KatanaInternal.sln => WebListener.sln (100%) diff --git a/KatanaInternal.sln b/WebListener.sln similarity index 100% rename from KatanaInternal.sln rename to WebListener.sln From 742db6ad652c58c0dc0f7c0d05bc0c04deb9d0e5 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Sat, 15 Feb 2014 15:38:17 -0800 Subject: [PATCH 004/597] Change to the new abstractions. --- .../OwinServerFactory.cs | 2 +- .../OwinWebListener.cs | 7 +- .../CallEnvironment.Generated.cs | 1913 ----------------- .../CallEnvironment.Generated.tt | 316 --- .../RequestProcessing/CallEnvironment.cs | 165 -- .../RequestProcessing/Request.cs | 314 ++- .../RequestProcessing/RequestContext.cs | 183 +- .../RequestProcessing/Response.cs | 91 +- .../RequestProcessing/ResponseStream.cs | 2 +- .../project.json | 5 + .../AuthenticationTests.cs | 19 +- .../HttpsTests.cs | 45 +- .../OpaqueUpgradeTests.cs | 5 +- .../RequestBodyTests.cs | 47 +- .../RequestHeaderTests.cs | 8 +- .../RequestTests.cs | 69 +- .../ResponseBodyTests.cs | 46 +- .../ResponseHeaderTests.cs | 38 +- .../ResponseSendFileTests.cs | 87 +- .../ResponseTests.cs | 40 +- .../ServerTests.cs | 26 +- .../project.json | 6 +- 22 files changed, 645 insertions(+), 2789 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.cs delete mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.tt delete mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs index 6b0b205db7..fa90780375 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs @@ -26,7 +26,7 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func, Task>; + using AppFunc = Func; using LoggerFactoryFunc = Func, bool>>; /// diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index d6c1cd916a..5f7b8c3ffb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -18,7 +18,7 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func, Task>; + using AppFunc = Func; using LoggerFactoryFunc = Func, bool>>; using LoggerFunc = Func, bool>; @@ -518,7 +518,7 @@ namespace Microsoft.AspNet.Server.WebListener { // TODO: Make disconnect registration lazy RegisterForDisconnectNotification(requestContext); - await _appFunc(requestContext.Environment).SupressContext(); + await _appFunc(requestContext.Features).SupressContext(); await requestContext.ProcessResponseAsync().SupressContext(); } catch (Exception ex) @@ -832,7 +832,8 @@ namespace Microsoft.AspNet.Server.WebListener ulong connectionId = requestContext.Request.ConnectionId; CancellationToken ct = GetConnectionCancellation(connectionId); requestContext.Request.RegisterForDisconnect(ct); - requestContext.Environment.ConnectionDisconnect = ct; + // TODO: Need a feature equivalent for owin.CallCancelled. + // requestContext.Environment.ConnectionDisconnect = ct; } catch (Win32Exception exception) { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.cs deleted file mode 100644 index d0fe8d05ea..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.cs +++ /dev/null @@ -1,1913 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) Katana Contributors. All rights reserved. -// -//----------------------------------------------------------------------- -// - -using System; -using System.CodeDom.Compiler; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Security.Authentication.ExtendedProtection; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.AspNet.Server.WebListener -{ - using OpaqueUpgrade = Action, Func, Task>>; - - [GeneratedCode("TextTemplatingFileGenerator", "")] - internal partial class CallEnvironment - { - // Mark all fields with delay initialization support as set. - private UInt32 _flag0 = 0x43e00200u; - private UInt32 _flag1 = 0x1u; - // Mark all fields with delay initialization support as requiring initialization. - private UInt32 _initFlag0 = 0x43e00200u; - private UInt32 _initFlag1 = 0x1u; - - internal interface IPropertySource - { - Stream GetRequestBody(); - string GetRemoteIpAddress(); - string GetRemotePort(); - string GetLocalIpAddress(); - string GetLocalPort(); - bool GetIsLocal(); - bool TryGetChannelBinding(ref ChannelBinding value); - bool TryGetOpaqueUpgrade(ref OpaqueUpgrade value); - } - - private string _OwinVersion; - private CancellationToken _CallCancelled; - private string _RequestProtocol; - private string _RequestMethod; - private string _RequestScheme; - private string _RequestPathBase; - private string _RequestPath; - private string _RequestQueryString; - private IDictionary _RequestHeaders; - private Stream _RequestBody; - private IDictionary _ResponseHeaders; - private Stream _ResponseBody; - private int? _ResponseStatusCode; - private string _ResponseReasonPhrase; - private TextWriter _HostTraceOutput; - private string _HostAppName; - private string _HostAppMode; - private CancellationToken _OnAppDisposing; - private System.Security.Principal.IPrincipal _User; - private Action, object> _OnSendingHeaders; - private IDictionary _ServerCapabilities; - private string _RemoteIpAddress; - private string _RemotePort; - private string _LocalIpAddress; - private string _LocalPort; - private bool _IsLocal; - private object _ConnectionId; - private CancellationToken _ConnectionDisconnect; - private object _ClientCert; - private Func _LoadClientCert; - private ChannelBinding _ChannelBinding; - private Func _SendFileAsync; - private OpaqueUpgrade _OpaqueUpgrade; - private OwinWebListener _Listener; - - bool InitPropertyChannelBinding() - { - if (!_propertySource.TryGetChannelBinding(ref _ChannelBinding)) - { - _flag0 &= ~0x40000000u; - _initFlag0 &= ~0x40000000u; - return false; - } - _initFlag0 &= ~0x40000000u; - return true; - } - - bool InitPropertyOpaqueUpgrade() - { - if (!_propertySource.TryGetOpaqueUpgrade(ref _OpaqueUpgrade)) - { - _flag1 &= ~0x1u; - _initFlag1 &= ~0x1u; - return false; - } - _initFlag1 &= ~0x1u; - return true; - } - - internal string OwinVersion - { - get - { - return _OwinVersion; - } - set - { - _flag0 |= 0x1u; - _OwinVersion = value; - } - } - - internal CancellationToken CallCancelled - { - get - { - return _CallCancelled; - } - set - { - _flag0 |= 0x2u; - _CallCancelled = value; - } - } - - internal string RequestProtocol - { - get - { - return _RequestProtocol; - } - set - { - _flag0 |= 0x4u; - _RequestProtocol = value; - } - } - - internal string RequestMethod - { - get - { - return _RequestMethod; - } - set - { - _flag0 |= 0x8u; - _RequestMethod = value; - } - } - - internal string RequestScheme - { - get - { - return _RequestScheme; - } - set - { - _flag0 |= 0x10u; - _RequestScheme = value; - } - } - - internal string RequestPathBase - { - get - { - return _RequestPathBase; - } - set - { - _flag0 |= 0x20u; - _RequestPathBase = value; - } - } - - internal string RequestPath - { - get - { - return _RequestPath; - } - set - { - _flag0 |= 0x40u; - _RequestPath = value; - } - } - - internal string RequestQueryString - { - get - { - return _RequestQueryString; - } - set - { - _flag0 |= 0x80u; - _RequestQueryString = value; - } - } - - internal IDictionary RequestHeaders - { - get - { - return _RequestHeaders; - } - set - { - _flag0 |= 0x100u; - _RequestHeaders = value; - } - } - - internal Stream RequestBody - { - get - { - if (((_initFlag0 & 0x200u) != 0)) - { - _RequestBody = _propertySource.GetRequestBody(); - _initFlag0 &= ~0x200u; - } - return _RequestBody; - } - set - { - _initFlag0 &= ~0x200u; - _flag0 |= 0x200u; - _RequestBody = value; - } - } - - internal IDictionary ResponseHeaders - { - get - { - return _ResponseHeaders; - } - set - { - _flag0 |= 0x400u; - _ResponseHeaders = value; - } - } - - internal Stream ResponseBody - { - get - { - return _ResponseBody; - } - set - { - _flag0 |= 0x800u; - _ResponseBody = value; - } - } - - internal int? ResponseStatusCode - { - get - { - return _ResponseStatusCode; - } - set - { - _flag0 |= 0x1000u; - _ResponseStatusCode = value; - } - } - - internal string ResponseReasonPhrase - { - get - { - return _ResponseReasonPhrase; - } - set - { - _flag0 |= 0x2000u; - _ResponseReasonPhrase = value; - } - } - - internal TextWriter HostTraceOutput - { - get - { - return _HostTraceOutput; - } - set - { - _flag0 |= 0x4000u; - _HostTraceOutput = value; - } - } - - internal string HostAppName - { - get - { - return _HostAppName; - } - set - { - _flag0 |= 0x8000u; - _HostAppName = value; - } - } - - internal string HostAppMode - { - get - { - return _HostAppMode; - } - set - { - _flag0 |= 0x10000u; - _HostAppMode = value; - } - } - - internal CancellationToken OnAppDisposing - { - get - { - return _OnAppDisposing; - } - set - { - _flag0 |= 0x20000u; - _OnAppDisposing = value; - } - } - - internal System.Security.Principal.IPrincipal User - { - get - { - return _User; - } - set - { - _flag0 |= 0x40000u; - _User = value; - } - } - - internal Action, object> OnSendingHeaders - { - get - { - return _OnSendingHeaders; - } - set - { - _flag0 |= 0x80000u; - _OnSendingHeaders = value; - } - } - - internal IDictionary ServerCapabilities - { - get - { - return _ServerCapabilities; - } - set - { - _flag0 |= 0x100000u; - _ServerCapabilities = value; - } - } - - internal string RemoteIpAddress - { - get - { - if (((_initFlag0 & 0x200000u) != 0)) - { - _RemoteIpAddress = _propertySource.GetRemoteIpAddress(); - _initFlag0 &= ~0x200000u; - } - return _RemoteIpAddress; - } - set - { - _initFlag0 &= ~0x200000u; - _flag0 |= 0x200000u; - _RemoteIpAddress = value; - } - } - - internal string RemotePort - { - get - { - if (((_initFlag0 & 0x400000u) != 0)) - { - _RemotePort = _propertySource.GetRemotePort(); - _initFlag0 &= ~0x400000u; - } - return _RemotePort; - } - set - { - _initFlag0 &= ~0x400000u; - _flag0 |= 0x400000u; - _RemotePort = value; - } - } - - internal string LocalIpAddress - { - get - { - if (((_initFlag0 & 0x800000u) != 0)) - { - _LocalIpAddress = _propertySource.GetLocalIpAddress(); - _initFlag0 &= ~0x800000u; - } - return _LocalIpAddress; - } - set - { - _initFlag0 &= ~0x800000u; - _flag0 |= 0x800000u; - _LocalIpAddress = value; - } - } - - internal string LocalPort - { - get - { - if (((_initFlag0 & 0x1000000u) != 0)) - { - _LocalPort = _propertySource.GetLocalPort(); - _initFlag0 &= ~0x1000000u; - } - return _LocalPort; - } - set - { - _initFlag0 &= ~0x1000000u; - _flag0 |= 0x1000000u; - _LocalPort = value; - } - } - - internal bool IsLocal - { - get - { - if (((_initFlag0 & 0x2000000u) != 0)) - { - _IsLocal = _propertySource.GetIsLocal(); - _initFlag0 &= ~0x2000000u; - } - return _IsLocal; - } - set - { - _initFlag0 &= ~0x2000000u; - _flag0 |= 0x2000000u; - _IsLocal = value; - } - } - - internal object ConnectionId - { - get - { - return _ConnectionId; - } - set - { - _flag0 |= 0x4000000u; - _ConnectionId = value; - } - } - - internal CancellationToken ConnectionDisconnect - { - get - { - return _ConnectionDisconnect; - } - set - { - _flag0 |= 0x8000000u; - _ConnectionDisconnect = value; - } - } - - internal object ClientCert - { - get - { - return _ClientCert; - } - set - { - _flag0 |= 0x10000000u; - _ClientCert = value; - } - } - - internal Func LoadClientCert - { - get - { - return _LoadClientCert; - } - set - { - _flag0 |= 0x20000000u; - _LoadClientCert = value; - } - } - - internal ChannelBinding ChannelBinding - { - get - { - if (((_initFlag0 & 0x40000000u) != 0)) - { - InitPropertyChannelBinding(); - } - return _ChannelBinding; - } - set - { - _initFlag0 &= ~0x40000000u; - _flag0 |= 0x40000000u; - _ChannelBinding = value; - } - } - - internal Func SendFileAsync - { - get - { - return _SendFileAsync; - } - set - { - _flag0 |= 0x80000000u; - _SendFileAsync = value; - } - } - - internal OpaqueUpgrade OpaqueUpgrade - { - get - { - if (((_initFlag1 & 0x1u) != 0)) - { - InitPropertyOpaqueUpgrade(); - } - return _OpaqueUpgrade; - } - set - { - _initFlag1 &= ~0x1u; - _flag1 |= 0x1u; - _OpaqueUpgrade = value; - } - } - - internal OwinWebListener Listener - { - get - { - return _Listener; - } - set - { - _flag1 |= 0x2u; - _Listener = value; - } - } - - private bool PropertiesContainsKey(string key) - { - switch (key.Length) - { - case 11: - if (((_flag0 & 0x40000u) != 0) && string.Equals(key, "server.User", StringComparison.Ordinal)) - { - return true; - } - break; - case 12: - if (((_flag0 & 0x1u) != 0) && string.Equals(key, "owin.Version", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x8000u) != 0) && string.Equals(key, "host.AppName", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x10000u) != 0) && string.Equals(key, "host.AppMode", StringComparison.Ordinal)) - { - return true; - } - break; - case 14: - if (((_flag0 & 0x2000000u) != 0) && string.Equals(key, "server.IsLocal", StringComparison.Ordinal)) - { - return true; - } - if (((_flag1 & 0x1u) != 0) && string.Equals(key, "opaque.Upgrade", StringComparison.Ordinal)) - { - if (((_initFlag1 & 0x1u) == 0) || InitPropertyOpaqueUpgrade()) - { - return true; - } - } - break; - case 16: - if (((_flag0 & 0x40u) != 0) && string.Equals(key, "owin.RequestPath", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x200u) != 0) && string.Equals(key, "owin.RequestBody", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x4000u) != 0) && string.Equals(key, "host.TraceOutput", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x1000000u) != 0) && string.Equals(key, "server.LocalPort", StringComparison.Ordinal)) - { - return true; - } - break; - case 17: - if (((_flag0 & 0x800u) != 0) && string.Equals(key, "owin.ResponseBody", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x400000u) != 0) && string.Equals(key, "server.RemotePort", StringComparison.Ordinal)) - { - return true; - } - break; - case 18: - if (((_flag0 & 0x2u) != 0) && string.Equals(key, "owin.CallCancelled", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x8u) != 0) && string.Equals(key, "owin.RequestMethod", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x10u) != 0) && string.Equals(key, "owin.RequestScheme", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x40000000u) != 0) && string.Equals(key, "ssl.ChannelBinding", StringComparison.Ordinal)) - { - if (((_initFlag0 & 0x40000000u) == 0) || InitPropertyChannelBinding()) - { - return true; - } - } - if (((_flag0 & 0x80000000u) != 0) && string.Equals(key, "sendfile.SendAsync", StringComparison.Ordinal)) - { - return true; - } - break; - case 19: - if (((_flag0 & 0x100u) != 0) && string.Equals(key, "owin.RequestHeaders", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x20000u) != 0) && string.Equals(key, "host.OnAppDisposing", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x100000u) != 0) && string.Equals(key, "server.Capabilities", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x4000000u) != 0) && string.Equals(key, "server.ConnectionId", StringComparison.Ordinal)) - { - return true; - } - break; - case 20: - if (((_flag0 & 0x4u) != 0) && string.Equals(key, "owin.RequestProtocol", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x20u) != 0) && string.Equals(key, "owin.RequestPathBase", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x400u) != 0) && string.Equals(key, "owin.ResponseHeaders", StringComparison.Ordinal)) - { - return true; - } - break; - case 21: - if (((_flag0 & 0x800000u) != 0) && string.Equals(key, "server.LocalIpAddress", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x10000000u) != 0) && string.Equals(key, "ssl.ClientCertificate", StringComparison.Ordinal)) - { - return true; - } - break; - case 22: - if (((_flag0 & 0x200000u) != 0) && string.Equals(key, "server.RemoteIpAddress", StringComparison.Ordinal)) - { - return true; - } - break; - case 23: - if (((_flag0 & 0x80u) != 0) && string.Equals(key, "owin.RequestQueryString", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x1000u) != 0) && string.Equals(key, "owin.ResponseStatusCode", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x80000u) != 0) && string.Equals(key, "server.OnSendingHeaders", StringComparison.Ordinal)) - { - return true; - } - if (((_flag0 & 0x20000000u) != 0) && string.Equals(key, "ssl.LoadClientCertAsync", StringComparison.Ordinal)) - { - return true; - } - break; - case 25: - if (((_flag0 & 0x2000u) != 0) && string.Equals(key, "owin.ResponseReasonPhrase", StringComparison.Ordinal)) - { - return true; - } - break; - case 27: - if (((_flag0 & 0x8000000u) != 0) && string.Equals(key, "server.ConnectionDisconnect", StringComparison.Ordinal)) - { - return true; - } - break; - case 51: - if (((_flag1 & 0x2u) != 0) && string.Equals(key, "Microsoft.AspNet.Server.WebListener.OwinWebListener", StringComparison.Ordinal)) - { - return true; - } - break; - } - return false; - } - - private bool PropertiesTryGetValue(string key, out object value) - { - switch (key.Length) - { - case 11: - if (((_flag0 & 0x40000u) != 0) && string.Equals(key, "server.User", StringComparison.Ordinal)) - { - value = User; - return true; - } - break; - case 12: - if (((_flag0 & 0x1u) != 0) && string.Equals(key, "owin.Version", StringComparison.Ordinal)) - { - value = OwinVersion; - return true; - } - if (((_flag0 & 0x8000u) != 0) && string.Equals(key, "host.AppName", StringComparison.Ordinal)) - { - value = HostAppName; - return true; - } - if (((_flag0 & 0x10000u) != 0) && string.Equals(key, "host.AppMode", StringComparison.Ordinal)) - { - value = HostAppMode; - return true; - } - break; - case 14: - if (((_flag0 & 0x2000000u) != 0) && string.Equals(key, "server.IsLocal", StringComparison.Ordinal)) - { - value = IsLocal; - return true; - } - if (((_flag1 & 0x1u) != 0) && string.Equals(key, "opaque.Upgrade", StringComparison.Ordinal)) - { - value = OpaqueUpgrade; - // Delayed initialization in the property getter may determine that the element is not actually present - if (!((_flag1 & 0x1u) != 0)) - { - value = default(OpaqueUpgrade); - return false; - } - return true; - } - break; - case 16: - if (((_flag0 & 0x40u) != 0) && string.Equals(key, "owin.RequestPath", StringComparison.Ordinal)) - { - value = RequestPath; - return true; - } - if (((_flag0 & 0x200u) != 0) && string.Equals(key, "owin.RequestBody", StringComparison.Ordinal)) - { - value = RequestBody; - return true; - } - if (((_flag0 & 0x4000u) != 0) && string.Equals(key, "host.TraceOutput", StringComparison.Ordinal)) - { - value = HostTraceOutput; - return true; - } - if (((_flag0 & 0x1000000u) != 0) && string.Equals(key, "server.LocalPort", StringComparison.Ordinal)) - { - value = LocalPort; - return true; - } - break; - case 17: - if (((_flag0 & 0x800u) != 0) && string.Equals(key, "owin.ResponseBody", StringComparison.Ordinal)) - { - value = ResponseBody; - return true; - } - if (((_flag0 & 0x400000u) != 0) && string.Equals(key, "server.RemotePort", StringComparison.Ordinal)) - { - value = RemotePort; - return true; - } - break; - case 18: - if (((_flag0 & 0x2u) != 0) && string.Equals(key, "owin.CallCancelled", StringComparison.Ordinal)) - { - value = CallCancelled; - return true; - } - if (((_flag0 & 0x8u) != 0) && string.Equals(key, "owin.RequestMethod", StringComparison.Ordinal)) - { - value = RequestMethod; - return true; - } - if (((_flag0 & 0x10u) != 0) && string.Equals(key, "owin.RequestScheme", StringComparison.Ordinal)) - { - value = RequestScheme; - return true; - } - if (((_flag0 & 0x40000000u) != 0) && string.Equals(key, "ssl.ChannelBinding", StringComparison.Ordinal)) - { - value = ChannelBinding; - // Delayed initialization in the property getter may determine that the element is not actually present - if (!((_flag0 & 0x40000000u) != 0)) - { - value = default(ChannelBinding); - return false; - } - return true; - } - if (((_flag0 & 0x80000000u) != 0) && string.Equals(key, "sendfile.SendAsync", StringComparison.Ordinal)) - { - value = SendFileAsync; - return true; - } - break; - case 19: - if (((_flag0 & 0x100u) != 0) && string.Equals(key, "owin.RequestHeaders", StringComparison.Ordinal)) - { - value = RequestHeaders; - return true; - } - if (((_flag0 & 0x20000u) != 0) && string.Equals(key, "host.OnAppDisposing", StringComparison.Ordinal)) - { - value = OnAppDisposing; - return true; - } - if (((_flag0 & 0x100000u) != 0) && string.Equals(key, "server.Capabilities", StringComparison.Ordinal)) - { - value = ServerCapabilities; - return true; - } - if (((_flag0 & 0x4000000u) != 0) && string.Equals(key, "server.ConnectionId", StringComparison.Ordinal)) - { - value = ConnectionId; - return true; - } - break; - case 20: - if (((_flag0 & 0x4u) != 0) && string.Equals(key, "owin.RequestProtocol", StringComparison.Ordinal)) - { - value = RequestProtocol; - return true; - } - if (((_flag0 & 0x20u) != 0) && string.Equals(key, "owin.RequestPathBase", StringComparison.Ordinal)) - { - value = RequestPathBase; - return true; - } - if (((_flag0 & 0x400u) != 0) && string.Equals(key, "owin.ResponseHeaders", StringComparison.Ordinal)) - { - value = ResponseHeaders; - return true; - } - break; - case 21: - if (((_flag0 & 0x800000u) != 0) && string.Equals(key, "server.LocalIpAddress", StringComparison.Ordinal)) - { - value = LocalIpAddress; - return true; - } - if (((_flag0 & 0x10000000u) != 0) && string.Equals(key, "ssl.ClientCertificate", StringComparison.Ordinal)) - { - value = ClientCert; - return true; - } - break; - case 22: - if (((_flag0 & 0x200000u) != 0) && string.Equals(key, "server.RemoteIpAddress", StringComparison.Ordinal)) - { - value = RemoteIpAddress; - return true; - } - break; - case 23: - if (((_flag0 & 0x80u) != 0) && string.Equals(key, "owin.RequestQueryString", StringComparison.Ordinal)) - { - value = RequestQueryString; - return true; - } - if (((_flag0 & 0x1000u) != 0) && string.Equals(key, "owin.ResponseStatusCode", StringComparison.Ordinal)) - { - value = ResponseStatusCode; - return true; - } - if (((_flag0 & 0x80000u) != 0) && string.Equals(key, "server.OnSendingHeaders", StringComparison.Ordinal)) - { - value = OnSendingHeaders; - return true; - } - if (((_flag0 & 0x20000000u) != 0) && string.Equals(key, "ssl.LoadClientCertAsync", StringComparison.Ordinal)) - { - value = LoadClientCert; - return true; - } - break; - case 25: - if (((_flag0 & 0x2000u) != 0) && string.Equals(key, "owin.ResponseReasonPhrase", StringComparison.Ordinal)) - { - value = ResponseReasonPhrase; - return true; - } - break; - case 27: - if (((_flag0 & 0x8000000u) != 0) && string.Equals(key, "server.ConnectionDisconnect", StringComparison.Ordinal)) - { - value = ConnectionDisconnect; - return true; - } - break; - case 51: - if (((_flag1 & 0x2u) != 0) && string.Equals(key, "Microsoft.AspNet.Server.WebListener.OwinWebListener", StringComparison.Ordinal)) - { - value = Listener; - return true; - } - break; - } - value = null; - return false; - } - - private bool PropertiesTrySetValue(string key, object value) - { - switch (key.Length) - { - case 11: - if (string.Equals(key, "server.User", StringComparison.Ordinal)) - { - User = (System.Security.Principal.IPrincipal)value; - return true; - } - break; - case 12: - if (string.Equals(key, "owin.Version", StringComparison.Ordinal)) - { - OwinVersion = (string)value; - return true; - } - if (string.Equals(key, "host.AppName", StringComparison.Ordinal)) - { - HostAppName = (string)value; - return true; - } - if (string.Equals(key, "host.AppMode", StringComparison.Ordinal)) - { - HostAppMode = (string)value; - return true; - } - break; - case 14: - if (string.Equals(key, "server.IsLocal", StringComparison.Ordinal)) - { - IsLocal = (bool)value; - return true; - } - if (string.Equals(key, "opaque.Upgrade", StringComparison.Ordinal)) - { - OpaqueUpgrade = (OpaqueUpgrade)value; - return true; - } - break; - case 16: - if (string.Equals(key, "owin.RequestPath", StringComparison.Ordinal)) - { - RequestPath = (string)value; - return true; - } - if (string.Equals(key, "owin.RequestBody", StringComparison.Ordinal)) - { - RequestBody = (Stream)value; - return true; - } - if (string.Equals(key, "host.TraceOutput", StringComparison.Ordinal)) - { - HostTraceOutput = (TextWriter)value; - return true; - } - if (string.Equals(key, "server.LocalPort", StringComparison.Ordinal)) - { - LocalPort = (string)value; - return true; - } - break; - case 17: - if (string.Equals(key, "owin.ResponseBody", StringComparison.Ordinal)) - { - ResponseBody = (Stream)value; - return true; - } - if (string.Equals(key, "server.RemotePort", StringComparison.Ordinal)) - { - RemotePort = (string)value; - return true; - } - break; - case 18: - if (string.Equals(key, "owin.CallCancelled", StringComparison.Ordinal)) - { - CallCancelled = (CancellationToken)value; - return true; - } - if (string.Equals(key, "owin.RequestMethod", StringComparison.Ordinal)) - { - RequestMethod = (string)value; - return true; - } - if (string.Equals(key, "owin.RequestScheme", StringComparison.Ordinal)) - { - RequestScheme = (string)value; - return true; - } - if (string.Equals(key, "ssl.ChannelBinding", StringComparison.Ordinal)) - { - ChannelBinding = (ChannelBinding)value; - return true; - } - if (string.Equals(key, "sendfile.SendAsync", StringComparison.Ordinal)) - { - SendFileAsync = (Func)value; - return true; - } - break; - case 19: - if (string.Equals(key, "owin.RequestHeaders", StringComparison.Ordinal)) - { - RequestHeaders = (IDictionary)value; - return true; - } - if (string.Equals(key, "host.OnAppDisposing", StringComparison.Ordinal)) - { - OnAppDisposing = (CancellationToken)value; - return true; - } - if (string.Equals(key, "server.Capabilities", StringComparison.Ordinal)) - { - ServerCapabilities = (IDictionary)value; - return true; - } - if (string.Equals(key, "server.ConnectionId", StringComparison.Ordinal)) - { - ConnectionId = (object)value; - return true; - } - break; - case 20: - if (string.Equals(key, "owin.RequestProtocol", StringComparison.Ordinal)) - { - RequestProtocol = (string)value; - return true; - } - if (string.Equals(key, "owin.RequestPathBase", StringComparison.Ordinal)) - { - RequestPathBase = (string)value; - return true; - } - if (string.Equals(key, "owin.ResponseHeaders", StringComparison.Ordinal)) - { - ResponseHeaders = (IDictionary)value; - return true; - } - break; - case 21: - if (string.Equals(key, "server.LocalIpAddress", StringComparison.Ordinal)) - { - LocalIpAddress = (string)value; - return true; - } - if (string.Equals(key, "ssl.ClientCertificate", StringComparison.Ordinal)) - { - ClientCert = (object)value; - return true; - } - break; - case 22: - if (string.Equals(key, "server.RemoteIpAddress", StringComparison.Ordinal)) - { - RemoteIpAddress = (string)value; - return true; - } - break; - case 23: - if (string.Equals(key, "owin.RequestQueryString", StringComparison.Ordinal)) - { - RequestQueryString = (string)value; - return true; - } - if (string.Equals(key, "owin.ResponseStatusCode", StringComparison.Ordinal)) - { - ResponseStatusCode = (int?)value; - return true; - } - if (string.Equals(key, "server.OnSendingHeaders", StringComparison.Ordinal)) - { - OnSendingHeaders = (Action, object>)value; - return true; - } - if (string.Equals(key, "ssl.LoadClientCertAsync", StringComparison.Ordinal)) - { - LoadClientCert = (Func)value; - return true; - } - break; - case 25: - if (string.Equals(key, "owin.ResponseReasonPhrase", StringComparison.Ordinal)) - { - ResponseReasonPhrase = (string)value; - return true; - } - break; - case 27: - if (string.Equals(key, "server.ConnectionDisconnect", StringComparison.Ordinal)) - { - ConnectionDisconnect = (CancellationToken)value; - return true; - } - break; - case 51: - if (string.Equals(key, "Microsoft.AspNet.Server.WebListener.OwinWebListener", StringComparison.Ordinal)) - { - Listener = (OwinWebListener)value; - return true; - } - break; - } - return false; - } - - private bool PropertiesTryRemove(string key) - { - switch (key.Length) - { - case 11: - if (((_flag0 & 0x40000u) != 0) && string.Equals(key, "server.User", StringComparison.Ordinal)) - { - _flag0 &= ~0x40000u; - _User = default(System.Security.Principal.IPrincipal); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 12: - if (((_flag0 & 0x1u) != 0) && string.Equals(key, "owin.Version", StringComparison.Ordinal)) - { - _flag0 &= ~0x1u; - _OwinVersion = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x8000u) != 0) && string.Equals(key, "host.AppName", StringComparison.Ordinal)) - { - _flag0 &= ~0x8000u; - _HostAppName = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x10000u) != 0) && string.Equals(key, "host.AppMode", StringComparison.Ordinal)) - { - _flag0 &= ~0x10000u; - _HostAppMode = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 14: - if (((_flag0 & 0x2000000u) != 0) && string.Equals(key, "server.IsLocal", StringComparison.Ordinal)) - { - _initFlag0 &= ~0x2000000u; - _flag0 &= ~0x2000000u; - _IsLocal = default(bool); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag1 & 0x1u) != 0) && string.Equals(key, "opaque.Upgrade", StringComparison.Ordinal)) - { - _initFlag1 &= ~0x1u; - _flag1 &= ~0x1u; - _OpaqueUpgrade = default(OpaqueUpgrade); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 16: - if (((_flag0 & 0x40u) != 0) && string.Equals(key, "owin.RequestPath", StringComparison.Ordinal)) - { - _flag0 &= ~0x40u; - _RequestPath = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x200u) != 0) && string.Equals(key, "owin.RequestBody", StringComparison.Ordinal)) - { - _initFlag0 &= ~0x200u; - _flag0 &= ~0x200u; - _RequestBody = default(Stream); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x4000u) != 0) && string.Equals(key, "host.TraceOutput", StringComparison.Ordinal)) - { - _flag0 &= ~0x4000u; - _HostTraceOutput = default(TextWriter); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x1000000u) != 0) && string.Equals(key, "server.LocalPort", StringComparison.Ordinal)) - { - _initFlag0 &= ~0x1000000u; - _flag0 &= ~0x1000000u; - _LocalPort = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 17: - if (((_flag0 & 0x800u) != 0) && string.Equals(key, "owin.ResponseBody", StringComparison.Ordinal)) - { - _flag0 &= ~0x800u; - _ResponseBody = default(Stream); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x400000u) != 0) && string.Equals(key, "server.RemotePort", StringComparison.Ordinal)) - { - _initFlag0 &= ~0x400000u; - _flag0 &= ~0x400000u; - _RemotePort = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 18: - if (((_flag0 & 0x2u) != 0) && string.Equals(key, "owin.CallCancelled", StringComparison.Ordinal)) - { - _flag0 &= ~0x2u; - _CallCancelled = default(CancellationToken); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x8u) != 0) && string.Equals(key, "owin.RequestMethod", StringComparison.Ordinal)) - { - _flag0 &= ~0x8u; - _RequestMethod = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x10u) != 0) && string.Equals(key, "owin.RequestScheme", StringComparison.Ordinal)) - { - _flag0 &= ~0x10u; - _RequestScheme = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x40000000u) != 0) && string.Equals(key, "ssl.ChannelBinding", StringComparison.Ordinal)) - { - _initFlag0 &= ~0x40000000u; - _flag0 &= ~0x40000000u; - _ChannelBinding = default(ChannelBinding); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x80000000u) != 0) && string.Equals(key, "sendfile.SendAsync", StringComparison.Ordinal)) - { - _flag0 &= ~0x80000000u; - _SendFileAsync = default(Func); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 19: - if (((_flag0 & 0x100u) != 0) && string.Equals(key, "owin.RequestHeaders", StringComparison.Ordinal)) - { - _flag0 &= ~0x100u; - _RequestHeaders = default(IDictionary); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x20000u) != 0) && string.Equals(key, "host.OnAppDisposing", StringComparison.Ordinal)) - { - _flag0 &= ~0x20000u; - _OnAppDisposing = default(CancellationToken); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x100000u) != 0) && string.Equals(key, "server.Capabilities", StringComparison.Ordinal)) - { - _flag0 &= ~0x100000u; - _ServerCapabilities = default(IDictionary); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x4000000u) != 0) && string.Equals(key, "server.ConnectionId", StringComparison.Ordinal)) - { - _flag0 &= ~0x4000000u; - _ConnectionId = default(object); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 20: - if (((_flag0 & 0x4u) != 0) && string.Equals(key, "owin.RequestProtocol", StringComparison.Ordinal)) - { - _flag0 &= ~0x4u; - _RequestProtocol = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x20u) != 0) && string.Equals(key, "owin.RequestPathBase", StringComparison.Ordinal)) - { - _flag0 &= ~0x20u; - _RequestPathBase = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x400u) != 0) && string.Equals(key, "owin.ResponseHeaders", StringComparison.Ordinal)) - { - _flag0 &= ~0x400u; - _ResponseHeaders = default(IDictionary); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 21: - if (((_flag0 & 0x800000u) != 0) && string.Equals(key, "server.LocalIpAddress", StringComparison.Ordinal)) - { - _initFlag0 &= ~0x800000u; - _flag0 &= ~0x800000u; - _LocalIpAddress = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x10000000u) != 0) && string.Equals(key, "ssl.ClientCertificate", StringComparison.Ordinal)) - { - _flag0 &= ~0x10000000u; - _ClientCert = default(object); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 22: - if (((_flag0 & 0x200000u) != 0) && string.Equals(key, "server.RemoteIpAddress", StringComparison.Ordinal)) - { - _initFlag0 &= ~0x200000u; - _flag0 &= ~0x200000u; - _RemoteIpAddress = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 23: - if (((_flag0 & 0x80u) != 0) && string.Equals(key, "owin.RequestQueryString", StringComparison.Ordinal)) - { - _flag0 &= ~0x80u; - _RequestQueryString = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x1000u) != 0) && string.Equals(key, "owin.ResponseStatusCode", StringComparison.Ordinal)) - { - _flag0 &= ~0x1000u; - _ResponseStatusCode = default(int?); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x80000u) != 0) && string.Equals(key, "server.OnSendingHeaders", StringComparison.Ordinal)) - { - _flag0 &= ~0x80000u; - _OnSendingHeaders = default(Action, object>); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - if (((_flag0 & 0x20000000u) != 0) && string.Equals(key, "ssl.LoadClientCertAsync", StringComparison.Ordinal)) - { - _flag0 &= ~0x20000000u; - _LoadClientCert = default(Func); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 25: - if (((_flag0 & 0x2000u) != 0) && string.Equals(key, "owin.ResponseReasonPhrase", StringComparison.Ordinal)) - { - _flag0 &= ~0x2000u; - _ResponseReasonPhrase = default(string); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 27: - if (((_flag0 & 0x8000000u) != 0) && string.Equals(key, "server.ConnectionDisconnect", StringComparison.Ordinal)) - { - _flag0 &= ~0x8000000u; - _ConnectionDisconnect = default(CancellationToken); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - case 51: - if (((_flag1 & 0x2u) != 0) && string.Equals(key, "Microsoft.AspNet.Server.WebListener.OwinWebListener", StringComparison.Ordinal)) - { - _flag1 &= ~0x2u; - _Listener = default(OwinWebListener); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } - break; - } - return false; - } - - private IEnumerable PropertiesKeys() - { - if (((_flag0 & 0x1u) != 0)) - { - yield return "owin.Version"; - } - if (((_flag0 & 0x2u) != 0)) - { - yield return "owin.CallCancelled"; - } - if (((_flag0 & 0x4u) != 0)) - { - yield return "owin.RequestProtocol"; - } - if (((_flag0 & 0x8u) != 0)) - { - yield return "owin.RequestMethod"; - } - if (((_flag0 & 0x10u) != 0)) - { - yield return "owin.RequestScheme"; - } - if (((_flag0 & 0x20u) != 0)) - { - yield return "owin.RequestPathBase"; - } - if (((_flag0 & 0x40u) != 0)) - { - yield return "owin.RequestPath"; - } - if (((_flag0 & 0x80u) != 0)) - { - yield return "owin.RequestQueryString"; - } - if (((_flag0 & 0x100u) != 0)) - { - yield return "owin.RequestHeaders"; - } - if (((_flag0 & 0x200u) != 0)) - { - yield return "owin.RequestBody"; - } - if (((_flag0 & 0x400u) != 0)) - { - yield return "owin.ResponseHeaders"; - } - if (((_flag0 & 0x800u) != 0)) - { - yield return "owin.ResponseBody"; - } - if (((_flag0 & 0x1000u) != 0)) - { - yield return "owin.ResponseStatusCode"; - } - if (((_flag0 & 0x2000u) != 0)) - { - yield return "owin.ResponseReasonPhrase"; - } - if (((_flag0 & 0x4000u) != 0)) - { - yield return "host.TraceOutput"; - } - if (((_flag0 & 0x8000u) != 0)) - { - yield return "host.AppName"; - } - if (((_flag0 & 0x10000u) != 0)) - { - yield return "host.AppMode"; - } - if (((_flag0 & 0x20000u) != 0)) - { - yield return "host.OnAppDisposing"; - } - if (((_flag0 & 0x40000u) != 0)) - { - yield return "server.User"; - } - if (((_flag0 & 0x80000u) != 0)) - { - yield return "server.OnSendingHeaders"; - } - if (((_flag0 & 0x100000u) != 0)) - { - yield return "server.Capabilities"; - } - if (((_flag0 & 0x200000u) != 0)) - { - yield return "server.RemoteIpAddress"; - } - if (((_flag0 & 0x400000u) != 0)) - { - yield return "server.RemotePort"; - } - if (((_flag0 & 0x800000u) != 0)) - { - yield return "server.LocalIpAddress"; - } - if (((_flag0 & 0x1000000u) != 0)) - { - yield return "server.LocalPort"; - } - if (((_flag0 & 0x2000000u) != 0)) - { - yield return "server.IsLocal"; - } - if (((_flag0 & 0x4000000u) != 0)) - { - yield return "server.ConnectionId"; - } - if (((_flag0 & 0x8000000u) != 0)) - { - yield return "server.ConnectionDisconnect"; - } - if (((_flag0 & 0x10000000u) != 0)) - { - yield return "ssl.ClientCertificate"; - } - if (((_flag0 & 0x20000000u) != 0)) - { - yield return "ssl.LoadClientCertAsync"; - } - if (((_flag0 & 0x40000000u) != 0)) - { - if (((_initFlag0 & 0x40000000u) == 0) || InitPropertyChannelBinding()) - { - yield return "ssl.ChannelBinding"; - } - } - if (((_flag0 & 0x80000000u) != 0)) - { - yield return "sendfile.SendAsync"; - } - if (((_flag1 & 0x1u) != 0)) - { - if (((_initFlag1 & 0x1u) == 0) || InitPropertyOpaqueUpgrade()) - { - yield return "opaque.Upgrade"; - } - } - if (((_flag1 & 0x2u) != 0)) - { - yield return "Microsoft.AspNet.Server.WebListener.OwinWebListener"; - } - } - - private IEnumerable PropertiesValues() - { - if (((_flag0 & 0x1u) != 0)) - { - yield return OwinVersion; - } - if (((_flag0 & 0x2u) != 0)) - { - yield return CallCancelled; - } - if (((_flag0 & 0x4u) != 0)) - { - yield return RequestProtocol; - } - if (((_flag0 & 0x8u) != 0)) - { - yield return RequestMethod; - } - if (((_flag0 & 0x10u) != 0)) - { - yield return RequestScheme; - } - if (((_flag0 & 0x20u) != 0)) - { - yield return RequestPathBase; - } - if (((_flag0 & 0x40u) != 0)) - { - yield return RequestPath; - } - if (((_flag0 & 0x80u) != 0)) - { - yield return RequestQueryString; - } - if (((_flag0 & 0x100u) != 0)) - { - yield return RequestHeaders; - } - if (((_flag0 & 0x200u) != 0)) - { - yield return RequestBody; - } - if (((_flag0 & 0x400u) != 0)) - { - yield return ResponseHeaders; - } - if (((_flag0 & 0x800u) != 0)) - { - yield return ResponseBody; - } - if (((_flag0 & 0x1000u) != 0)) - { - yield return ResponseStatusCode; - } - if (((_flag0 & 0x2000u) != 0)) - { - yield return ResponseReasonPhrase; - } - if (((_flag0 & 0x4000u) != 0)) - { - yield return HostTraceOutput; - } - if (((_flag0 & 0x8000u) != 0)) - { - yield return HostAppName; - } - if (((_flag0 & 0x10000u) != 0)) - { - yield return HostAppMode; - } - if (((_flag0 & 0x20000u) != 0)) - { - yield return OnAppDisposing; - } - if (((_flag0 & 0x40000u) != 0)) - { - yield return User; - } - if (((_flag0 & 0x80000u) != 0)) - { - yield return OnSendingHeaders; - } - if (((_flag0 & 0x100000u) != 0)) - { - yield return ServerCapabilities; - } - if (((_flag0 & 0x200000u) != 0)) - { - yield return RemoteIpAddress; - } - if (((_flag0 & 0x400000u) != 0)) - { - yield return RemotePort; - } - if (((_flag0 & 0x800000u) != 0)) - { - yield return LocalIpAddress; - } - if (((_flag0 & 0x1000000u) != 0)) - { - yield return LocalPort; - } - if (((_flag0 & 0x2000000u) != 0)) - { - yield return IsLocal; - } - if (((_flag0 & 0x4000000u) != 0)) - { - yield return ConnectionId; - } - if (((_flag0 & 0x8000000u) != 0)) - { - yield return ConnectionDisconnect; - } - if (((_flag0 & 0x10000000u) != 0)) - { - yield return ClientCert; - } - if (((_flag0 & 0x20000000u) != 0)) - { - yield return LoadClientCert; - } - if (((_flag0 & 0x40000000u) != 0)) - { - if (((_initFlag0 & 0x40000000u) == 0) || InitPropertyChannelBinding()) - { - yield return ChannelBinding; - } - } - if (((_flag0 & 0x80000000u) != 0)) - { - yield return SendFileAsync; - } - if (((_flag1 & 0x1u) != 0)) - { - if (((_initFlag1 & 0x1u) == 0) || InitPropertyOpaqueUpgrade()) - { - yield return OpaqueUpgrade; - } - } - if (((_flag1 & 0x2u) != 0)) - { - yield return Listener; - } - } - - private IEnumerable> PropertiesEnumerable() - { - if (((_flag0 & 0x1u) != 0)) - { - yield return new KeyValuePair("owin.Version", OwinVersion); - } - if (((_flag0 & 0x2u) != 0)) - { - yield return new KeyValuePair("owin.CallCancelled", CallCancelled); - } - if (((_flag0 & 0x4u) != 0)) - { - yield return new KeyValuePair("owin.RequestProtocol", RequestProtocol); - } - if (((_flag0 & 0x8u) != 0)) - { - yield return new KeyValuePair("owin.RequestMethod", RequestMethod); - } - if (((_flag0 & 0x10u) != 0)) - { - yield return new KeyValuePair("owin.RequestScheme", RequestScheme); - } - if (((_flag0 & 0x20u) != 0)) - { - yield return new KeyValuePair("owin.RequestPathBase", RequestPathBase); - } - if (((_flag0 & 0x40u) != 0)) - { - yield return new KeyValuePair("owin.RequestPath", RequestPath); - } - if (((_flag0 & 0x80u) != 0)) - { - yield return new KeyValuePair("owin.RequestQueryString", RequestQueryString); - } - if (((_flag0 & 0x100u) != 0)) - { - yield return new KeyValuePair("owin.RequestHeaders", RequestHeaders); - } - if (((_flag0 & 0x200u) != 0)) - { - yield return new KeyValuePair("owin.RequestBody", RequestBody); - } - if (((_flag0 & 0x400u) != 0)) - { - yield return new KeyValuePair("owin.ResponseHeaders", ResponseHeaders); - } - if (((_flag0 & 0x800u) != 0)) - { - yield return new KeyValuePair("owin.ResponseBody", ResponseBody); - } - if (((_flag0 & 0x1000u) != 0)) - { - yield return new KeyValuePair("owin.ResponseStatusCode", ResponseStatusCode); - } - if (((_flag0 & 0x2000u) != 0)) - { - yield return new KeyValuePair("owin.ResponseReasonPhrase", ResponseReasonPhrase); - } - if (((_flag0 & 0x4000u) != 0)) - { - yield return new KeyValuePair("host.TraceOutput", HostTraceOutput); - } - if (((_flag0 & 0x8000u) != 0)) - { - yield return new KeyValuePair("host.AppName", HostAppName); - } - if (((_flag0 & 0x10000u) != 0)) - { - yield return new KeyValuePair("host.AppMode", HostAppMode); - } - if (((_flag0 & 0x20000u) != 0)) - { - yield return new KeyValuePair("host.OnAppDisposing", OnAppDisposing); - } - if (((_flag0 & 0x40000u) != 0)) - { - yield return new KeyValuePair("server.User", User); - } - if (((_flag0 & 0x80000u) != 0)) - { - yield return new KeyValuePair("server.OnSendingHeaders", OnSendingHeaders); - } - if (((_flag0 & 0x100000u) != 0)) - { - yield return new KeyValuePair("server.Capabilities", ServerCapabilities); - } - if (((_flag0 & 0x200000u) != 0)) - { - yield return new KeyValuePair("server.RemoteIpAddress", RemoteIpAddress); - } - if (((_flag0 & 0x400000u) != 0)) - { - yield return new KeyValuePair("server.RemotePort", RemotePort); - } - if (((_flag0 & 0x800000u) != 0)) - { - yield return new KeyValuePair("server.LocalIpAddress", LocalIpAddress); - } - if (((_flag0 & 0x1000000u) != 0)) - { - yield return new KeyValuePair("server.LocalPort", LocalPort); - } - if (((_flag0 & 0x2000000u) != 0)) - { - yield return new KeyValuePair("server.IsLocal", IsLocal); - } - if (((_flag0 & 0x4000000u) != 0)) - { - yield return new KeyValuePair("server.ConnectionId", ConnectionId); - } - if (((_flag0 & 0x8000000u) != 0)) - { - yield return new KeyValuePair("server.ConnectionDisconnect", ConnectionDisconnect); - } - if (((_flag0 & 0x10000000u) != 0)) - { - yield return new KeyValuePair("ssl.ClientCertificate", ClientCert); - } - if (((_flag0 & 0x20000000u) != 0)) - { - yield return new KeyValuePair("ssl.LoadClientCertAsync", LoadClientCert); - } - if (((_flag0 & 0x40000000u) != 0)) - { - if (((_initFlag0 & 0x40000000u) == 0) || InitPropertyChannelBinding()) - { - yield return new KeyValuePair("ssl.ChannelBinding", ChannelBinding); - } - } - if (((_flag0 & 0x80000000u) != 0)) - { - yield return new KeyValuePair("sendfile.SendAsync", SendFileAsync); - } - if (((_flag1 & 0x1u) != 0)) - { - if (((_initFlag1 & 0x1u) == 0) || InitPropertyOpaqueUpgrade()) - { - yield return new KeyValuePair("opaque.Upgrade", OpaqueUpgrade); - } - } - if (((_flag1 & 0x2u) != 0)) - { - yield return new KeyValuePair("Microsoft.AspNet.Server.WebListener.OwinWebListener", Listener); - } - } - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.tt b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.tt deleted file mode 100644 index 41a1b3db06..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.Generated.tt +++ /dev/null @@ -1,316 +0,0 @@ -<#@ template language="C#" #> -<#@ assembly name="System.Core.dll" #> -<#@ import namespace="System.Linq" #> -<# -var Init = new {Yes = new object(), No = new object(), Maybe = new object()}; - -var props = new[] -{ -// owin standard keys - new {Key="owin.Version", Type="string", Name="OwinVersion", Init=Init.No}, - new {Key="owin.CallCancelled", Type="CancellationToken", Name="CallCancelled", Init=Init.No}, - - new {Key="owin.RequestProtocol", Type="string", Name="RequestProtocol", Init=Init.No}, - new {Key="owin.RequestMethod", Type="string", Name="RequestMethod", Init=Init.No}, - new {Key="owin.RequestScheme", Type="string", Name="RequestScheme", Init=Init.No}, - new {Key="owin.RequestPathBase", Type="string", Name="RequestPathBase", Init=Init.No}, - new {Key="owin.RequestPath", Type="string", Name="RequestPath", Init=Init.No}, - new {Key="owin.RequestQueryString", Type="string", Name="RequestQueryString", Init=Init.No}, - new {Key="owin.RequestHeaders", Type="IDictionary", Name="RequestHeaders", Init=Init.No}, - new {Key="owin.RequestBody", Type="Stream", Name="RequestBody", Init=Init.Yes}, - - new {Key="owin.ResponseHeaders", Type="IDictionary", Name="ResponseHeaders", Init=Init.No}, - new {Key="owin.ResponseBody", Type="Stream", Name="ResponseBody", Init=Init.No}, - new {Key="owin.ResponseStatusCode", Type="int?", Name="ResponseStatusCode", Init=Init.No}, - new {Key="owin.ResponseReasonPhrase", Type="string", Name="ResponseReasonPhrase", Init=Init.No}, - -// defacto host keys - new {Key="host.TraceOutput", Type="TextWriter", Name="HostTraceOutput", Init=Init.No}, - new {Key="host.AppName", Type="string", Name="HostAppName", Init=Init.No}, - new {Key="host.AppMode", Type="string", Name="HostAppMode", Init=Init.No}, - new {Key="host.OnAppDisposing", Type="CancellationToken", Name="OnAppDisposing", Init=Init.No}, - new {Key="server.User", Type="System.Security.Principal.IPrincipal", Name="User", Init=Init.No}, - new {Key="server.OnSendingHeaders", Type="Action, object>", Name="OnSendingHeaders", Init=Init.No}, - new {Key="server.Capabilities", Type="IDictionary", Name="ServerCapabilities", Init=Init.No}, - -// ServerVariable keys - new {Key="server.RemoteIpAddress", Type="string", Name="RemoteIpAddress", Init=Init.Yes}, - new {Key="server.RemotePort", Type="string", Name="RemotePort", Init=Init.Yes}, - new {Key="server.LocalIpAddress", Type="string", Name="LocalIpAddress", Init=Init.Yes}, - new {Key="server.LocalPort", Type="string", Name="LocalPort", Init=Init.Yes}, - new {Key="server.IsLocal", Type="bool", Name="IsLocal", Init=Init.Yes}, - new {Key="server.ConnectionId", Type="object", Name="ConnectionId", Init=Init.No}, - new {Key="server.ConnectionDisconnect", Type="CancellationToken", Name="ConnectionDisconnect", Init=Init.No}, - -// SSL - new { Key="ssl.ClientCertificate", Type="object", Name="ClientCert", Init=Init.No}, - new { Key="ssl.LoadClientCertAsync", Type="Func", Name="LoadClientCert", Init=Init.No }, - new { Key="ssl.ChannelBinding", Type="ChannelBinding", Name="ChannelBinding", Init=Init.Maybe }, - -// SendFile keys - new {Key="sendfile.SendAsync", Type="Func", Name="SendFileAsync", Init=Init.No}, - -// Opaque keys - new {Key="opaque.Upgrade", Type="OpaqueUpgrade", Name="OpaqueUpgrade", Init=Init.Maybe}, - -// Server specific keys - new { Key="Microsoft.AspNet.Server.WebListener.OwinWebListener", Type="OwinWebListener", Name="Listener", Init=Init.No}, -}.Select((prop, Index)=>new {prop.Key, prop.Type, prop.Name, prop.Init, Index}); - -var lengths = props.OrderBy(prop=>prop.Key.Length).GroupBy(prop=>prop.Key.Length); - -Func IsSet = Index => "((_flag" + (Index / 32) + " & 0x" + (1<<(Index % 32)).ToString("x") + "u) != 0)"; -Func Set = Index => "_flag" + (Index / 32) + " |= 0x" + (1<<(Index % 32)).ToString("x") + "u"; -Func Clear = Index => "_flag" + (Index / 32) + " &= ~0x" + (1<<(Index % 32)).ToString("x") + "u"; - -Func IsInitRequired = Index => "((_initFlag" + (Index / 32) + " & 0x" + (1<<(Index % 32)).ToString("x") + "u) != 0)"; -Func IsInitCompleted = Index => "((_initFlag" + (Index / 32) + " & 0x" + (1<<(Index % 32)).ToString("x") + "u) == 0)"; -Func CompleteInit = Index => "_initFlag" + (Index / 32) + " &= ~0x" + (1<<(Index % 32)).ToString("x") + "u"; - -#> -//----------------------------------------------------------------------- -// -// Copyright (c) Katana Contributors. All rights reserved. -// -//----------------------------------------------------------------------- -// - -using System; -using System.CodeDom.Compiler; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Security.Authentication.ExtendedProtection; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Owin.Host.WebListener -{ - using OpaqueUpgrade = Action, Func, Task>>; - - [GeneratedCode("TextTemplatingFileGenerator", "")] - internal partial class CallEnvironment - { - // Mark all fields with delay initialization support as set. - private UInt32 _flag0 = 0x<#=props.Aggregate(0, (agg,p) => agg | (((p.Init != Init.No) && (p.Index/32==0) ? 1:0)<u; - private UInt32 _flag1 = 0x<#=props.Aggregate(0, (agg,p) => agg | (((p.Init != Init.No) && (p.Index/32==1) ? 1:0)<u; - // Mark all fields with delay initialization support as requiring initialization. - private UInt32 _initFlag0 = 0x<#=props.Aggregate(0, (agg,p) => agg | (((p.Init != Init.No) && (p.Index/32==0) ? 1:0)<u; - private UInt32 _initFlag1 = 0x<#=props.Aggregate(0, (agg,p) => agg | (((p.Init != Init.No) && (p.Index/32==1) ? 1:0)<u; - - internal interface IPropertySource - { -<# foreach(var prop in props) { #> -<# if (prop.Init == Init.Yes) { #> - <#=prop.Type#> Get<#=prop.Name#>(); -<# } #> -<# if (prop.Init == Init.Maybe) { #> - bool TryGet<#=prop.Name#>(ref <#=prop.Type#> value); -<# } #> -<# } #> - } - -<# foreach(var prop in props) { #> - private <#=prop.Type#> _<#=prop.Name#>; -<# } #> - -<# foreach(var prop in props) { #> -<# // call TryGet once if init flag is set, clear value flag if TryGet returns false -if (prop.Init == Init.Maybe) { #> - bool InitProperty<#=prop.Name#>() - { - if (!_propertySource.TryGet<#=prop.Name#>(ref _<#=prop.Name#>)) - { - <#=Clear(prop.Index)#>; - <#=CompleteInit(prop.Index)#>; - return false; - } - <#=CompleteInit(prop.Index)#>; - return true; - } - -<# } #> -<# } #> -<# foreach(var prop in props) { #> - internal <#=prop.Type#> <#=prop.Name#> - { - get - { -<# // call Get once if init flag is set -if (prop.Init == Init.Yes) { #> - if (<#=IsInitRequired(prop.Index)#>) - { - _<#=prop.Name#> = _propertySource.Get<#=prop.Name#>(); - <#=CompleteInit(prop.Index)#>; - } -<# } #> -<# // call TryGet once if init flag is set, clear value flag if TryGet returns false -if (prop.Init == Init.Maybe) { #> - if (<#=IsInitRequired(prop.Index)#>) - { - InitProperty<#=prop.Name#>(); - } -<# } #> - return _<#=prop.Name#>; - } - set - { -<# // clear init flag - the assigned value is definitive -if (prop.Init != Init.No) { #> - <#=CompleteInit(prop.Index)#>; -<# } #> - <#=Set(prop.Index)#>; - _<#=prop.Name#> = value; - } - } - -<# } #> - private bool PropertiesContainsKey(string key) - { - switch (key.Length) - { -<# foreach(var length in lengths) { #> - case <#=length.Key#>: -<# foreach(var prop in length) { #> - if (<#=IsSet(prop.Index)#> && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) - { -<# // variable maybe init might revert -if (prop.Init == Init.Maybe) { #> - if (<#=IsInitCompleted(prop.Index)#> || InitProperty<#=prop.Name#>()) - { - return true; - } -<# } else { #> - return true; -<# } #> - } -<# } #> - break; -<# } #> - } - return false; - } - - private bool PropertiesTryGetValue(string key, out object value) - { - switch (key.Length) - { -<# foreach(var length in lengths) { #> - case <#=length.Key#>: -<# foreach(var prop in length) { #> - if (<#=IsSet(prop.Index)#> && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) - { - value = <#=prop.Name#>; -<# if (prop.Init == Init.Maybe) { #> - // Delayed initialization in the property getter may determine that the element is not actually present - if (!<#=IsSet(prop.Index)#>) - { - value = default(<#=prop.Type#>); - return false; - } -<# } #> - return true; - } -<# } #> - break; -<# } #> - } - value = null; - return false; - } - - private bool PropertiesTrySetValue(string key, object value) - { - switch (key.Length) - { -<# foreach(var length in lengths) { #> - case <#=length.Key#>: -<# foreach(var prop in length) { #> - if (string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) - { - <#=prop.Name#> = (<#=prop.Type#>)value; - return true; - } -<# } #> - break; -<# } #> - } - return false; - } - - private bool PropertiesTryRemove(string key) - { - switch (key.Length) - { -<# foreach(var length in lengths) { #> - case <#=length.Key#>: -<# foreach(var prop in length) { #> - if (<#=IsSet(prop.Index)#> && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) - { -<# if (prop.Init != Init.No) { #> - <#=CompleteInit(prop.Index)#>; -<# } #> - <#=Clear(prop.Index)#>; - _<#=prop.Name#> = default(<#=prop.Type#>); - // This can return true incorrectly for values that delayed initialization may determine are not actually present. - return true; - } -<# } #> - break; -<# } #> - } - return false; - } - - private IEnumerable PropertiesKeys() - { -<# foreach(var prop in props) { #> - if (<#=IsSet(prop.Index)#>) - { -<# if (prop.Init == Init.Maybe) { #> - if (<#=IsInitCompleted(prop.Index)#> || InitProperty<#=prop.Name#>()) - { - yield return "<#=prop.Key#>"; - } -<# } else { #> - yield return "<#=prop.Key#>"; -<# } #> - } -<# } #> - } - - private IEnumerable PropertiesValues() - { -<# foreach(var prop in props) { #> - if (<#=IsSet(prop.Index)#>) - { -<# if (prop.Init == Init.Maybe) { #> - if (<#=IsInitCompleted(prop.Index)#> || InitProperty<#=prop.Name#>()) - { - yield return <#=prop.Name#>; - } -<# } else { #> - yield return <#=prop.Name#>; -<# } #> - } -<# } #> - } - - private IEnumerable> PropertiesEnumerable() - { -<# foreach(var prop in props) { #> - if (<#=IsSet(prop.Index)#>) - { -<# if (prop.Init == Init.Maybe) { #> - if (<#=IsInitCompleted(prop.Index)#> || InitProperty<#=prop.Name#>()) - { - yield return new KeyValuePair("<#=prop.Key#>", <#=prop.Name#>); - } -<# } else { #> - yield return new KeyValuePair("<#=prop.Key#>", <#=prop.Name#>); -<# } #> - } -<# } #> - } - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.cs deleted file mode 100644 index 360a2ea245..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/CallEnvironment.cs +++ /dev/null @@ -1,165 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- -// Copyright 2011-2012 Katana contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -namespace Microsoft.AspNet.Server.WebListener -{ - internal partial class CallEnvironment : IDictionary - { - private static readonly IDictionary WeakNilEnvironment = new NilEnvDictionary(); - - private readonly IPropertySource _propertySource; - private IDictionary _extra = WeakNilEnvironment; - - internal CallEnvironment(IPropertySource propertySource) - { - _propertySource = propertySource; - } - - private IDictionary Extra - { - get { return _extra; } - } - - private IDictionary StrongExtra - { - get - { - if (_extra == WeakNilEnvironment) - { - Interlocked.CompareExchange(ref _extra, new Dictionary(), WeakNilEnvironment); - } - return _extra; - } - } - - internal bool IsExtraDictionaryCreated - { - get { return _extra != WeakNilEnvironment; } - } - - public object this[string key] - { - get - { - object value; - return PropertiesTryGetValue(key, out value) ? value : Extra[key]; - } - set - { - if (!PropertiesTrySetValue(key, value)) - { - StrongExtra[key] = value; - } - } - } - - public void Add(string key, object value) - { - if (!PropertiesTrySetValue(key, value)) - { - StrongExtra.Add(key, value); - } - } - - public bool ContainsKey(string key) - { - return PropertiesContainsKey(key) || Extra.ContainsKey(key); - } - - public ICollection Keys - { - get { return PropertiesKeys().Concat(Extra.Keys).ToArray(); } - } - - public bool Remove(string key) - { - // Although this is a mutating operation, Extra is used instead of StrongExtra, - // because if a real dictionary has not been allocated the default behavior of the - // nil dictionary is perfectly fine. - return PropertiesTryRemove(key) || Extra.Remove(key); - } - - public bool TryGetValue(string key, out object value) - { - return PropertiesTryGetValue(key, out value) || Extra.TryGetValue(key, out value); - } - - public ICollection Values - { - get { return PropertiesValues().Concat(Extra.Values).ToArray(); } - } - - public void Add(KeyValuePair item) - { - ((IDictionary)this).Add(item.Key, item.Value); - } - - public void Clear() - { - foreach (var key in PropertiesKeys()) - { - PropertiesTryRemove(key); - } - Extra.Clear(); - } - - public bool Contains(KeyValuePair item) - { - object value; - return ((IDictionary)this).TryGetValue(item.Key, out value) && Object.Equals(value, item.Value); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - PropertiesEnumerable().Concat(Extra).ToArray().CopyTo(array, arrayIndex); - } - - public int Count - { - get { return PropertiesKeys().Count() + Extra.Count; } - } - - public bool IsReadOnly - { - get { return false; } - } - - public bool Remove(KeyValuePair item) - { - return ((IDictionary)this).Contains(item) && - ((IDictionary)this).Remove(item.Key); - } - - public IEnumerator> GetEnumerator() - { - return PropertiesEnumerable().Concat(Extra).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IDictionary)this).GetEnumerator(); - } - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index 86b25185fb..dcf3100e30 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -10,14 +10,18 @@ using System.Globalization; using System.IO; using System.Net; using System.Runtime.InteropServices; +#if NET45 using System.Security.Authentication.ExtendedProtection; +using System.Security.Cryptography.X509Certificates; +#endif using System.Security.Principal; -using System.Text; using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.HttpFeature; namespace Microsoft.AspNet.Server.WebListener { - internal sealed unsafe class Request : IDisposable + internal sealed class Request : IHttpRequestInformation, IHttpConnection, IHttpTransportLayerSecurity, IDisposable { private RequestContext _requestContext; private NativeRequestContext _nativeRequestContext; @@ -27,29 +31,46 @@ namespace Microsoft.AspNet.Server.WebListener private ulong _contextId; private SslStatus _sslStatus; + private string _scheme; private string _httpMethod; private Version _httpVersion; + private string _httpProtocolVersion; - private Uri _requestUri; + // private Uri _requestUri; private string _rawUrl; private string _cookedUrlHost; private string _cookedUrlPath; private string _cookedUrlQuery; + private string _pathBase; + private string _path; - private RequestHeaders _headers; +#if NET45 + private X509Certificate _clientCert; +#endif + + private IDictionary _headers; private BoundaryType _contentBoundaryType; private long _contentLength; + private Stream _nativeStream; private Stream _requestStream; + private SocketAddress _localEndPoint; private SocketAddress _remoteEndPoint; +#if NET45 + private IPAddress _remoteIpAddress; + private IPAddress _localIpAddress; +#endif + private int? _remotePort; + private int? _localPort; + private bool? _isLocal; private IPrincipal _user; private bool _isDisposed = false; private CancellationTokenRegistration _disconnectRegistration; - internal Request(RequestContext httpContext, NativeRequestContext memoryBlob) + internal unsafe Request(RequestContext httpContext, NativeRequestContext memoryBlob) { // TODO: Verbose log _requestContext = httpContext; @@ -82,6 +103,24 @@ namespace Microsoft.AspNet.Server.WebListener _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } + Prefix prefix = httpContext.Server.UriPrefixes[(int)_contextId]; + string orriginalPath = RequestPath; + + // These paths are both unescaped already. + if (orriginalPath.Length == prefix.Path.Length - 1) + { + // They matched exactly except for the trailing slash. + _pathBase = orriginalPath; + _path = string.Empty; + } + else + { + // url: /base/path, prefix: /base/, base: /base, path: /path + // url: /, prefix: /, base: , path: / + _pathBase = orriginalPath.Substring(0, prefix.Path.Length - 1); + _path = orriginalPath.Substring(prefix.Path.Length - 1); + } + int major = memoryBlob.RequestBlob->Version.MajorVersion; int minor = memoryBlob.RequestBlob->Version.MinorVersion; if (major == 1 && minor == 1) @@ -155,16 +194,16 @@ namespace Microsoft.AspNet.Server.WebListener } } - // Without the leading ? - internal string Query + // With the leading ?, if any + public string QueryString { get { - if (!string.IsNullOrWhiteSpace(_cookedUrlQuery)) - { - return _cookedUrlQuery.Substring(1); - } - return string.Empty; + return _cookedUrlQuery ?? string.Empty; + } + set + { + _cookedUrlQuery = value; } } @@ -176,6 +215,25 @@ namespace Microsoft.AspNet.Server.WebListener } } +#if NET45 + X509Certificate IHttpTransportLayerSecurity.ClientCertificate + { + get + { + if (_clientCert == null) + { + // TODO: Sync + ((IHttpTransportLayerSecurity)this).LoadAsync().Wait(); + } + return _clientCert; + } + set + { + _clientCert = value; + } + } +#endif + // TODO: Move this to the constructor, that's where it will be called. internal long ContentLength64 { @@ -210,40 +268,101 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal IDictionary Headers + public IDictionary Headers { get { return _headers; } + set + { + if (value == null) + { + throw new ArgumentNullException("value"); + } + _headers = value; + } } - internal string HttpMethod + public string Method { get { return _httpMethod; } + set + { + _httpMethod = value; + } } - internal Stream InputStream + internal Stream NativeStream + { + get + { + if (_nativeStream == null) + { + // TODO: Move this to the constructor (or a lazy Env dictionary) + _nativeStream = HasEntityBody ? new RequestStream(RequestContext) : Stream.Null; + } + return _nativeStream; + } + } + + public Stream Body { get { if (_requestStream == null) { // TODO: Move this to the constructor (or a lazy Env dictionary) - _requestStream = HasEntityBody ? new RequestStream(RequestContext) : Stream.Null; + _requestStream = NativeStream; } return _requestStream; } + set + { + _requestStream = value; + } } - internal bool IsLocal + public string PathBase { get { - return LocalEndPoint.GetIPAddressString().Equals(RemoteEndPoint.GetIPAddressString()); + return _pathBase; + } + set + { + _pathBase = value; + } + } + + public string Path + { + get + { + return _path; + } + set + { + _path = value; + } + } + + public bool IsLocal + { + get + { + if (!_isLocal.HasValue) + { + _isLocal = LocalEndPoint.GetIPAddressString().Equals(RemoteEndPoint.GetIPAddressString()); + } + return _isLocal.Value; + } + set + { + _isLocal = value; } } @@ -254,7 +373,7 @@ namespace Microsoft.AspNet.Server.WebListener return _sslStatus != SslStatus.Insecure; } } - + /* internal string RawUrl { get @@ -262,7 +381,7 @@ namespace Microsoft.AspNet.Server.WebListener return _rawUrl; } } - + */ internal Version ProtocolVersion { get @@ -271,22 +390,34 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal string Protocol + public string Protocol { get { - if (_httpVersion.Major == 1) + if (_httpProtocolVersion == null) { - if (_httpVersion.Minor == 1) + if (_httpVersion.Major == 1) { - return "HTTP/1.1"; + if (_httpVersion.Minor == 1) + { + _httpProtocolVersion = "HTTP/1.1"; + } + else if (_httpVersion.Minor == 0) + { + _httpProtocolVersion = "HTTP/1.0"; + } } - else if (_httpVersion.Minor == 0) + else { - return "HTTP/1.0"; + _httpProtocolVersion = "HTTP/" + _httpVersion.ToString(2); } } - return "HTTP/" + _httpVersion.ToString(2); + return _httpProtocolVersion; + } + set + { + // TODO: Set _httpVersion? + _httpProtocolVersion = value; } } @@ -326,15 +457,87 @@ namespace Microsoft.AspNet.Server.WebListener return _localEndPoint; } } - - internal string RequestScheme +#if NET45 + public IPAddress RemoteIpAddress { get { - return IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; + if (_remoteIpAddress == null) + { + _remoteIpAddress = IPAddress.Parse(RemoteEndPoint.GetIPAddressString()); // TODO: Create directly from bytes + } + return _remoteIpAddress; + } + set + { + _remoteIpAddress = value; } } + public IPAddress LocalIpAddress + { + get + { + if (_localIpAddress == null) + { + _localIpAddress = IPAddress.Parse(LocalEndPoint.GetIPAddressString()); // TODO: Create directly from bytes + } + return _localIpAddress; + } + set + { + _localIpAddress = value; + } + } +#endif + public int RemotePort + { + get + { + if (!_remotePort.HasValue) + { + _remotePort = RemoteEndPoint.GetPort(); + } + return _remotePort.Value; + } + set + { + _remotePort = value; + } + } + + public int LocalPort + { + get + { + if (!_localPort.HasValue) + { + _localPort = LocalEndPoint.GetPort(); + } + return _localPort.Value; + } + set + { + _localPort = value; + } + } + + public string Scheme + { + get + { + if (_scheme == null) + { + _scheme = IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; + } + return _scheme; + } + set + { + _scheme = value; + } + } + /* internal Uri RequestUri { get @@ -348,7 +551,7 @@ namespace Microsoft.AspNet.Server.WebListener return _requestUri; } } - + */ internal string RequestPath { get @@ -391,6 +594,47 @@ namespace Microsoft.AspNet.Server.WebListener #endif } + // Populates the client certificate. The result may be null if there is no client cert. + // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to + // enable this, but it's unclear what Http.Sys would do. + async Task IHttpTransportLayerSecurity.LoadAsync() + { + if (SslStatus == SslStatus.Insecure) + { + // Non-SSL + return; + } + // TODO: Verbose log +#if NET45 + if (_clientCert != null) + { + return; + } + + ClientCertLoader certLoader = new ClientCertLoader(RequestContext); + try + { + await certLoader.LoadClientCertificateAsync().SupressContext(); + // Populate the environment. + if (certLoader.ClientCert != null) + { + _clientCert = certLoader.ClientCert; + } + // TODO: Expose errors and exceptions? + } + catch (Exception) + { + if (certLoader != null) + { + certLoader.Dispose(); + } + throw; + } +#else + throw new NotImplementedException(); +#endif + } + // Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be // disposed. internal void DetachBlob(NativeRequestContext memoryBlob) @@ -419,9 +663,9 @@ namespace Microsoft.AspNet.Server.WebListener _nativeRequestContext = null; } _disconnectRegistration.Dispose(); - if (_requestStream != null) + if (_nativeStream != null) { - _requestStream.Dispose(); + _nativeStream.Dispose(); } } @@ -435,9 +679,9 @@ namespace Microsoft.AspNet.Server.WebListener internal void SwitchToOpaqueMode() { - if (_requestStream == null || _requestStream == Stream.Null) + if (_nativeStream == null || _nativeStream == Stream.Null) { - _requestStream = new RequestStream(RequestContext); + _nativeStream = new RequestStream(RequestContext); } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs index 5cb122006c..934ed1eb87 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs @@ -15,17 +15,19 @@ using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; namespace Microsoft.AspNet.Server.WebListener { using LoggerFunc = Func, bool>; using OpaqueFunc = Func, Task>; - internal sealed class RequestContext : IDisposable, CallEnvironment.IPropertySource + internal sealed class RequestContext : IDisposable { private static readonly string[] ZeroContentLength = new[] { "0" }; - private CallEnvironment _environment; + private FeatureCollection _features; private OwinWebListener _server; private Request _request; private Response _response; @@ -41,17 +43,17 @@ namespace Microsoft.AspNet.Server.WebListener _memoryBlob = memoryBlob; _request = new Request(this, _memoryBlob); _response = new Response(this); - _environment = new CallEnvironment(this); _cts = new CancellationTokenSource(); - PopulateEnvironment(); + _features = new FeatureCollection(); + PopulateFeatures(); _request.ReleasePins(); } - internal CallEnvironment Environment + internal IFeatureCollection Features { - get { return _environment; } + get { return _features; } } internal Request Request @@ -99,105 +101,31 @@ namespace Microsoft.AspNet.Server.WebListener } } - private void PopulateEnvironment() + private void PopulateFeatures() { - // General - _environment.OwinVersion = Constants.OwinVersion; - _environment.CallCancelled = _cts.Token; + _features.Add(typeof(IHttpRequestInformation), Request); + _features.Add(typeof(IHttpConnection), Request); + if (Request.IsSecureConnection) + { + // TODO: Should this feature be conditional? Should we add this for HTTP requests? + _features.Add(typeof(IHttpTransportLayerSecurity), Request); + } + _features.Add(typeof(IHttpResponseInformation), Response); + _features.Add(typeof(IHttpSendFile), Response); + // TODO: + // _environment.CallCancelled = _cts.Token; + // _environment.User = _request.User; + // Opaque/WebSockets + // Channel binding + + /* // Server - _environment.ServerCapabilities = _server.Capabilities; _environment.Listener = _server; - - // Request - _environment.RequestProtocol = _request.Protocol; - _environment.RequestMethod = _request.HttpMethod; - _environment.RequestScheme = _request.RequestScheme; - _environment.RequestQueryString = _request.Query; - _environment.RequestHeaders = _request.Headers; - - SetPaths(); - - _environment.ConnectionId = _request.ConnectionId; - - if (_request.IsSecureConnection) - { - _environment.LoadClientCert = LoadClientCertificateAsync; - } - - if (_request.User != null) - { - _environment.User = _request.User; - } - - // Response - _environment.ResponseStatusCode = 200; - _environment.ResponseHeaders = _response.Headers; - _environment.ResponseBody = _response.OutputStream; - _environment.SendFileAsync = _response.SendFileAsync; - - _environment.OnSendingHeaders = _response.RegisterForOnSendingHeaders; - - Contract.Assert(!_environment.IsExtraDictionaryCreated, - "All server keys should have a reserved slot in the environment."); + _environment.ConnectionId = _request.ConnectionId; + */ } - - // Find the closest matching prefix and use it to separate the request path in to path and base path. - // Scheme and port must match. Path will use a longest match. Host names are more complicated due to - // wildcards, IP addresses, etc. - private void SetPaths() - { - Prefix prefix = _server.UriPrefixes[(int)Request.ContextId]; - string orriginalPath = _request.RequestPath; - - // These paths are both unescaped already. - if (orriginalPath.Length == prefix.Path.Length - 1) - { - // They matched exactly except for the trailing slash. - _environment.RequestPathBase = orriginalPath; - _environment.RequestPath = string.Empty; - } - else - { - // url: /base/path, prefix: /base/, base: /base, path: /path - // url: /, prefix: /, base: , path: / - _environment.RequestPathBase = orriginalPath.Substring(0, prefix.Path.Length - 1); - _environment.RequestPath = orriginalPath.Substring(prefix.Path.Length - 1); - } - } - - // Lazy environment init - - public Stream GetRequestBody() - { - return _request.InputStream; - } - - public string GetRemoteIpAddress() - { - return _request.RemoteEndPoint.GetIPAddressString(); - } - - public string GetRemotePort() - { - return _request.RemoteEndPoint.GetPort().ToString(CultureInfo.InvariantCulture.NumberFormat); - } - - public string GetLocalIpAddress() - { - return _request.LocalEndPoint.GetIPAddressString(); - } - - public string GetLocalPort() - { - return _request.LocalEndPoint.GetPort().ToString(CultureInfo.InvariantCulture.NumberFormat); - } - - public bool GetIsLocal() - { - return _request.IsLocal; - } - + /* public bool TryGetOpaqueUpgrade(ref Action, OpaqueFunc> value) { if (_request.IsUpgradable) @@ -213,6 +141,7 @@ namespace Microsoft.AspNet.Server.WebListener value = Server.GetChannelBinding(Request.ConnectionId, Request.IsSecureConnection); return value != null; } + */ public void Dispose() { @@ -290,42 +219,6 @@ namespace Microsoft.AspNet.Server.WebListener } } - // Populates the environment ClicentCertificate. The result may be null if there is no client cert. - // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to - // enable this, but it's unclear what Http.Sys would do. - private async Task LoadClientCertificateAsync() - { - if (Request.SslStatus == SslStatus.Insecure) - { - // Non-SSL - return; - } - // TODO: Verbose log -#if NET45 - ClientCertLoader certLoader = new ClientCertLoader(this); - try - { - await certLoader.LoadClientCertificateAsync().SupressContext(); - // Populate the environment. - if (certLoader.ClientCert != null) - { - Environment.ClientCert = certLoader.ClientCert; - } - // TODO: Expose errors and exceptions? - } - catch (Exception) - { - if (certLoader != null) - { - certLoader.Dispose(); - } - throw; - } -#else - throw new NotImplementedException(); -#endif - } - internal void OpaqueUpgrade(IDictionary parameters, OpaqueFunc callback) { // Parameters are ignored for now @@ -339,8 +232,8 @@ namespace Microsoft.AspNet.Server.WebListener } // Set the status code and reason phrase - Environment.ResponseStatusCode = (int)HttpStatusCode.SwitchingProtocols; - Environment.ResponseReasonPhrase = HttpReasonPhrase.Get(HttpStatusCode.SwitchingProtocols); + Response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; + Response.ReasonPhrase = HttpReasonPhrase.Get(HttpStatusCode.SwitchingProtocols); // Store the callback and process it after the stack unwind. _opaqueCallback = callback; @@ -351,7 +244,7 @@ namespace Microsoft.AspNet.Server.WebListener { // If an upgrade was requested, perform it if (!Response.SentHeaders && _opaqueCallback != null - && Environment.ResponseStatusCode == (int)HttpStatusCode.SwitchingProtocols) + && Response.StatusCode == (int)HttpStatusCode.SwitchingProtocols) { Response.SendOpaqueUpgrade(); @@ -368,21 +261,21 @@ namespace Microsoft.AspNet.Server.WebListener opaqueEnv[Constants.OpaqueVersionKey] = Constants.OpaqueVersion; // TODO: Separate CT? - opaqueEnv[Constants.OpaqueCallCancelledKey] = Environment.CallCancelled; + // opaqueEnv[Constants.OpaqueCallCancelledKey] = Environment.CallCancelled; Request.SwitchToOpaqueMode(); Response.SwitchToOpaqueMode(); - opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.InputStream, Response.OutputStream); + opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.NativeStream, Response.NativeStream); return opaqueEnv; } internal void SetFatalResponse() { - Environment.ResponseStatusCode = 500; - Environment.ResponseReasonPhrase = string.Empty; - Environment.ResponseHeaders.Clear(); - Environment.ResponseHeaders.Add(HttpKnownHeaderNames.ContentLength, ZeroContentLength); + Response.StatusCode = 500; + Response.ReasonPhrase = string.Empty; + Response.Headers.Clear(); + Response.Headers.Add(HttpKnownHeaderNames.ContentLength, ZeroContentLength); } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs index d25af63ed7..9f2ac4807d 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs @@ -14,14 +14,17 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.HttpFeature; namespace Microsoft.AspNet.Server.WebListener { - internal sealed unsafe class Response : IDisposable + internal sealed unsafe class Response : IHttpResponseInformation, IHttpSendFile, IDisposable { private ResponseState _responseState; private IDictionary _headers; - private ResponseStream _responseStream; + private string _reasonPhrase; + private ResponseStream _nativeStream; + private Stream _responseStream; private long _contentLength; private BoundaryType _boundaryType; private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE _nativeResponse; @@ -67,31 +70,55 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal Stream OutputStream + public int StatusCode + { + get { return _nativeResponse.StatusCode; } + set + { + if (value <= 100 || 999 < value) + { + throw new ArgumentOutOfRangeException("value", value, string.Format(Resources.Exception_InvalidStatusCode, value)); + } + _nativeResponse.StatusCode = (ushort)value; + } + } + + public string ReasonPhrase + { + get { return _reasonPhrase; } + set { _reasonPhrase = value; } + } + + internal ResponseStream NativeStream { get { CheckDisposed(); EnsureResponseStream(); - return _responseStream; + return _nativeStream; } } - internal int GetStatusCode() + public Stream Body { - int statusCode = _requestContext.Environment.ResponseStatusCode ?? 200; - if (statusCode <= 100 || statusCode > 999) + get { - // TODO: Move this validation to the dictionary facade so it throws when the app sets it, rather than durring send? - throw new InvalidOperationException(string.Format(Resources.Exception_InvalidStatusCode, statusCode)); + if (_responseStream == null) + { + _responseStream = NativeStream; + } + return _responseStream; + } + set + { + _responseStream = value; } - return statusCode; } internal string GetReasonPhrase(int statusCode) { // TODO: Validate user input for illegal chars, length limit, etc.? - string reasonPhrase = _requestContext.Environment.ResponseReasonPhrase; + string reasonPhrase = ReasonPhrase; if (string.IsNullOrWhiteSpace(reasonPhrase)) { // if the user hasn't set this, generated on the fly, if possible. @@ -124,11 +151,16 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal IDictionary Headers + public IDictionary Headers { - get + get { return _headers; } + set { - return _headers; + if (value == null) + { + throw new ArgumentNullException("value"); + } + _headers = value; } } @@ -142,6 +174,7 @@ namespace Microsoft.AspNet.Server.WebListener private Version GetProtocolVersion() { + /* Version requestVersion = Request.ProtocolVersion; Version responseVersion = requestVersion; string protocolVersion = RequestContext.Environment.Get(Constants.HttpResponseProtocolKey); @@ -170,7 +203,11 @@ namespace Microsoft.AspNet.Server.WebListener } // Return the lesser of the two versions. There are only two, so it it will always be 1.0. - return Constants.V1_0; + return Constants.V1_0;*/ + + // TODO: IHttpResponseInformation does not define a response protocol version. Http.Sys doesn't let + // us send anything but 1.1 anyways, but we could at least use it to set things like the connection header. + return Request.ProtocolVersion; } public void Dispose() @@ -188,7 +225,7 @@ namespace Microsoft.AspNet.Server.WebListener } // TODO: Verbose log EnsureResponseStream(); - _responseStream.Dispose(); + _nativeStream.Dispose(); _responseState = ResponseState.Closed; } } @@ -221,9 +258,9 @@ namespace Microsoft.AspNet.Server.WebListener private void EnsureResponseStream() { - if (_responseStream == null) + if (_nativeStream == null) { - _responseStream = new ResponseStream(RequestContext); + _nativeStream = new ResponseStream(RequestContext); } } @@ -266,8 +303,6 @@ namespace Microsoft.AspNet.Server.WebListener // TODO: Verbose log headers _responseState = ResponseState.SentHeaders; - - _nativeResponse.StatusCode = (ushort)GetStatusCode(); string reasonPhrase = GetReasonPhrase(_nativeResponse.StatusCode); /* @@ -369,7 +404,7 @@ namespace Microsoft.AspNet.Server.WebListener NotifyOnSendingHeaders(); // 401 - if (GetStatusCode() == (ushort)HttpStatusCode.Unauthorized) + if (StatusCode == (ushort)HttpStatusCode.Unauthorized) { RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(this); } @@ -468,7 +503,7 @@ namespace Microsoft.AspNet.Server.WebListener _boundaryType = BoundaryType.Chunked; } - if (CanSendResponseBody(_requestContext.Response.GetStatusCode())) + if (CanSendResponseBody(_requestContext.Response.StatusCode)) { _contentLength = -1; } @@ -708,25 +743,25 @@ namespace Microsoft.AspNet.Server.WebListener internal void CancelLastWrite(SafeHandle requestQueueHandle) { - if (_responseStream != null) + if (_nativeStream != null) { - _responseStream.CancelLastWrite(requestQueueHandle); + _nativeStream.CancelLastWrite(requestQueueHandle); } } - internal Task SendFileAsync(string fileName, long offset, long? count, CancellationToken cancel) + public Task SendFileAsync(string path, long offset, long? count, CancellationToken cancel) { EnsureResponseStream(); - return _responseStream.SendFileAsync(fileName, offset, count, cancel); + return _nativeStream.SendFileAsync(path, offset, count, cancel); } internal void SwitchToOpaqueMode() { EnsureResponseStream(); - _responseStream.SwitchToOpaqueMode(); + _nativeStream.SwitchToOpaqueMode(); } - internal void RegisterForOnSendingHeaders(Action callback, object state) + public void OnSendingHeaders(Action callback, object state) { IList, object>> actions = _onSendingHeadersActions; if (actions == null) diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs index 0177312901..84c29adefe 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs @@ -736,7 +736,7 @@ namespace Microsoft.AspNet.Server.WebListener } uint statusCode = 0; - if ((_requestContext.Response.BoundaryType == BoundaryType.Chunked || _requestContext.Response.BoundaryType == BoundaryType.None) && (String.Compare(_requestContext.Request.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase) != 0)) + if ((_requestContext.Response.BoundaryType == BoundaryType.Chunked || _requestContext.Response.BoundaryType == BoundaryType.None) && (String.Compare(_requestContext.Request.Method, "HEAD", StringComparison.OrdinalIgnoreCase) != 0)) { if (_requestContext.Response.BoundaryType == BoundaryType.None) { diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 0ba47798dd..cb109c3392 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,5 +1,10 @@ { "version": "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", + "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*" + }, "compilationOptions" : { "allowUnsafe": true }, "configurations": { "net45" : { }, diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs index d85855d66a..0259f84f43 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs @@ -9,12 +9,14 @@ using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.PipelineCore; using Xunit; using Xunit.Extensions; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class AuthenticationTests { @@ -49,7 +51,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(authType, env => { - env["owin.ResponseStatusCode"] = 401; + new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; return Task.FromResult(0); })) { @@ -65,7 +67,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests // TODO: Not implemented - Digest using (CreateServer(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationType.Basic, env => { - env["owin.ResponseStatusCode"] = 401; + new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; return Task.FromResult(0); })) { @@ -74,26 +76,27 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal("Kerberos, Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } } - + /* TODO: User [Theory] [InlineData(AuthenticationType.Kerberos)] [InlineData(AuthenticationType.Negotiate)] [InlineData(AuthenticationType.Ntlm)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented // [InlineData(AuthenticationType.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationType.Basic)] + [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | / *AuthenticationType.Digest |* / AuthenticationType.Basic)] public async Task AuthTypes_Login_Success(AuthenticationType authType) { int requestCount = 0; using (CreateServer(authType, env => { requestCount++; + / * // TODO: Expose user as feature. object obj; if (env.TryGetValue("server.User", out obj) && obj != null) { return Task.FromResult(0); - } - env["owin.ResponseStatusCode"] = 401; + }* / + new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; return Task.FromResult(0); })) { @@ -101,7 +104,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests response.EnsureSuccessStatusCode(); } } - + */ private IDisposable CreateServer(AuthenticationType authType, AppFunc app) { IDictionary properties = new Dictionary(); diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs index 98661a8380..c2e29eccde 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs @@ -11,11 +11,14 @@ using System.Net.Http; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class HttpsTests { @@ -39,10 +42,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] body = Encoding.UTF8.GetBytes("Hello World"); - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Content-Length"] = new string[] { body.Length.ToString() }; - return env.Get("owin.ResponseBody").WriteAsync(body, 0, body.Length); + httpContext.Response.ContentLength = body.Length; + return httpContext.Response.Body.WriteAsync(body, 0, body.Length); })) { string response = await SendRequestAsync(Address); @@ -55,12 +58,12 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - string input = new StreamReader(env.Get("owin.RequestBody")).ReadToEnd(); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + string input = new StreamReader(httpContext.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); byte[] body = Encoding.UTF8.GetBytes("Hello World"); - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Content-Length"] = new string[] { body.Length.ToString() }; - env.Get("owin.ResponseBody").Write(body, 0, body.Length); + httpContext.Response.ContentLength = body.Length; + httpContext.Response.Body.Write(body, 0, body.Length); return Task.FromResult(0); })) { @@ -72,38 +75,36 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { - X509Certificate clientCert = null; - using (CreateServer(env => + using (CreateServer(async env => { - var loadAsync = env.Get>("ssl.LoadClientCertAsync"); - loadAsync().Wait(); - clientCert = env.Get("ssl.ClientCertificate"); - return Task.FromResult(0); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var tls = httpContext.GetFeature(); + Assert.NotNull(tls); + await tls.LoadAsync(); + Assert.Null(tls.ClientCertificate); })) { string response = await SendRequestAsync(Address); Assert.Equal(string.Empty, response); - Assert.Null(clientCert); } } [Fact] public async Task Https_ClientCertRequested_ClientCertPresent() { - X509Certificate clientCert = null; - using (CreateServer(env => + using (CreateServer(async env => { - var loadAsync = env.Get>("ssl.LoadClientCertAsync"); - loadAsync().Wait(); - clientCert = env.Get("ssl.ClientCertificate"); - return Task.FromResult(0); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var tls = httpContext.GetFeature(); + Assert.NotNull(tls); + await tls.LoadAsync(); + Assert.NotNull(tls.ClientCertificate); })) { X509Certificate2 cert = FindClientCert(); Assert.NotNull(cert); string response = await SendRequestAsync(Address, cert); Assert.Equal(string.Empty, response); - Assert.NotNull(clientCert); } } diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs index 07c8610feb..e7ddf53495 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs @@ -3,7 +3,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // // ----------------------------------------------------------------------- - +/* TODO: Opaque using System; using System.Collections.Generic; using System.IO; @@ -17,7 +17,7 @@ using Xunit.Extensions; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; using OpaqueUpgrade = Action, Func, Task>>; public class OpaqueUpgradeTests @@ -322,3 +322,4 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } } } +*/ \ No newline at end of file diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs index 3687766ca1..640d0dc489 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs @@ -11,11 +11,13 @@ using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class RequestBodyTests { @@ -26,12 +28,11 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; - int read = env.Get("owin.RequestBody").Read(input, 0, input.Length); - - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Content-Length"] = new string[] { read.ToString() }; - env.Get("owin.ResponseBody").Write(input, 0, read); + int read = httpContext.Request.Body.Read(input, 0, input.Length); + httpContext.Response.ContentLength = read; + httpContext.Response.Body.Write(input, 0, read); return Task.FromResult(0); })) { @@ -45,32 +46,28 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(async env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; - int read = await env.Get("owin.RequestBody").ReadAsync(input, 0, input.Length); - - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Content-Length"] = new string[] { read.ToString() }; - await env.Get("owin.ResponseBody").WriteAsync(input, 0, read); + int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); + httpContext.Response.ContentLength = read; + await httpContext.Response.Body.WriteAsync(input, 0, read); })) { string response = await SendRequestAsync(Address, "Hello World"); Assert.Equal("Hello World", response); } } - +#if NET45 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { using (CreateServer(env => { - Stream requestStream = env.Get("owin.RequestBody"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; - int read = requestStream.EndRead(requestStream.BeginRead(input, 0, input.Length, null, null)); - - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Content-Length"] = new string[] { read.ToString() }; - Stream responseStream = env.Get("owin.ResponseBody"); - responseStream.EndWrite(responseStream.BeginWrite(input, 0, read, null, null)); + int read = httpContext.Request.Body.EndRead(httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); + httpContext.Response.ContentLength = read; + httpContext.Response.Body.EndWrite(httpContext.Response.Body.BeginWrite(input, 0, read, null, null)); return Task.FromResult(0); })) { @@ -78,18 +75,19 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal("Hello World", response); } } - +#endif [Fact] public async Task RequestBody_ReadSyncPartialBody_Success() { StaggardContent content = new StaggardContent(); using (CreateServer(env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[10]; - int read = env.Get("owin.RequestBody").Read(input, 0, input.Length); + int read = httpContext.Request.Body.Read(input, 0, input.Length); Assert.Equal(5, read); content.Block.Release(); - read = env.Get("owin.RequestBody").Read(input, 0, input.Length); + read = httpContext.Request.Body.Read(input, 0, input.Length); Assert.Equal(5, read); return Task.FromResult(0); })) @@ -105,11 +103,12 @@ namespace Microsoft.AspNet.Server.WebListener.Tests StaggardContent content = new StaggardContent(); using (CreateServer(async env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[10]; - int read = await env.Get("owin.RequestBody").ReadAsync(input, 0, input.Length); + int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(5, read); content.Block.Release(); - read = await env.Get("owin.RequestBody").ReadAsync(input, 0, input.Length); + read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(5, read); })) { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs index a322ea06d0..9e2828c50d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs @@ -10,11 +10,13 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class RequestHeaderTests { @@ -25,7 +27,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - var requestHeaders = env.Get>("owin.RequestHeaders"); + var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. // Assert.Equal(2, requestHeaders.Count); // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); @@ -44,7 +46,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - var requestHeaders = env.Get>("owin.RequestHeaders"); + var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; Assert.Equal(4, requestHeaders.Count); Assert.Equal("localhost:8080", requestHeaders.Get("Host")); Assert.Equal("close", requestHeaders.Get("Connection")); diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs index a99bdafa86..11c0ce59d1 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs @@ -11,12 +11,15 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.PipelineCore; using Xunit; using Xunit.Extensions; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class RequestTests { @@ -27,36 +30,40 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { // General keys - Assert.Equal("1.0", env.Get("owin.Version")); - Assert.True(env.Get("owin.CallCancelled").CanBeCanceled); + // TODO: Assert.True(env.Get("owin.CallCancelled").CanBeCanceled); + + var requestInfo = httpContext.GetFeature(); // Request Keys - Assert.Equal("GET", env.Get("owin.RequestMethod")); - Assert.Equal(Stream.Null, env.Get("owin.RequestBody")); - Assert.NotNull(env.Get>("owin.RequestHeaders")); - Assert.Equal("http", env.Get("owin.RequestScheme")); - Assert.Equal("/basepath", env.Get("owin.RequestPathBase")); - Assert.Equal("/SomePath", env.Get("owin.RequestPath")); - Assert.Equal("SomeQuery", env.Get("owin.RequestQueryString")); - Assert.Equal("HTTP/1.1", env.Get("owin.RequestProtocol")); + Assert.Equal("GET", requestInfo.Method); + Assert.Equal(Stream.Null, requestInfo.Body); + Assert.NotNull(requestInfo.Headers); + Assert.Equal("http", requestInfo.Scheme); + Assert.Equal("/basepath", requestInfo.PathBase); + Assert.Equal("/SomePath", requestInfo.Path); + Assert.Equal("?SomeQuery", requestInfo.QueryString); + Assert.Equal("HTTP/1.1", requestInfo.Protocol); // Server Keys - Assert.NotNull(env.Get>("server.Capabilities")); - Assert.Equal("::1", env.Get("server.RemoteIpAddress")); - Assert.NotNull(env.Get("server.RemotePort")); - Assert.Equal("::1", env.Get("server.LocalIpAddress")); - Assert.Equal("8080", env.Get("server.LocalPort")); - Assert.True(env.Get("server.IsLocal")); + // TODO: Assert.NotNull(env.Get>("server.Capabilities")); + + var connectionInfo = httpContext.GetFeature(); + Assert.Equal("::1", connectionInfo.RemoteIpAddress.ToString()); + Assert.NotEqual(0, connectionInfo.RemotePort); + Assert.Equal("::1", connectionInfo.LocalIpAddress.ToString()); + Assert.NotEqual(0, connectionInfo.LocalPort); + Assert.True(connectionInfo.IsLocal); // Note: Response keys are validated in the ResponseTests } catch (Exception ex) { byte[] body = Encoding.ASCII.GetBytes(ex.ToString()); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); + httpContext.Response.Body.Write(body, 0, body.Length); } return Task.FromResult(0); }, "http", "localhost", "8080", "/basepath")) @@ -78,21 +85,23 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - Uri uri = new Uri(requestUri); - string expectedQuery = uri.Query.Length > 0 ? uri.Query.Substring(1) : string.Empty; + var requestInfo = httpContext.GetFeature(); + var connectionInfo = httpContext.GetFeature(); + // Request Keys - Assert.Equal(scheme, env.Get("owin.RequestScheme")); - Assert.Equal(expectedPath, env.Get("owin.RequestPath")); - Assert.Equal(expectedPathBase, env.Get("owin.RequestPathBase")); - Assert.Equal(expectedQuery, env.Get("owin.RequestQueryString")); - Assert.Equal(port, env.Get("server.LocalPort")); + Assert.Equal(scheme, requestInfo.Scheme); + Assert.Equal(expectedPath, requestInfo.Path); + Assert.Equal(expectedPathBase, requestInfo.PathBase); + Assert.Equal(string.Empty, requestInfo.QueryString); + Assert.Equal(port, connectionInfo.LocalPort.ToString()); } catch (Exception ex) { byte[] body = Encoding.ASCII.GetBytes(ex.ToString()); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); + httpContext.Response.Body.Write(body, 0, body.Length); } return Task.FromResult(0); }, scheme, host, port, pathBase)) @@ -119,15 +128,17 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var requestInfo = httpContext.GetFeature(); try { - Assert.Equal(expectedPath, env.Get("owin.RequestPath")); - Assert.Equal(expectedPathBase, env.Get("owin.RequestPathBase")); + Assert.Equal(expectedPath, requestInfo.Path); + Assert.Equal(expectedPathBase, requestInfo.PathBase); } catch (Exception ex) { byte[] body = Encoding.ASCII.GetBytes(ex.ToString()); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); + httpContext.Response.Body.Write(body, 0, body.Length); } return Task.FromResult(0); })) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs index bc95cb305f..ddcdc4aa2e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs @@ -11,11 +11,14 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class ResponseBodyTests { @@ -26,8 +29,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); - return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.Body.Write(new byte[10], 0, 10); + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -45,8 +49,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["transfeR-Encoding"] = new string[] { " CHunked " }; - Stream stream = env.Get("owin.ResponseBody"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Request.Headers["transfeR-Encoding"] = " CHunked "; + Stream stream = httpContext.Response.Body; stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); stream.Write(new byte[10], 0, 10); return stream.WriteAsync(new byte[10], 0, 10); @@ -67,8 +72,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 30 " }; - Stream stream = env.Get("owin.ResponseBody"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.Headers["Content-lenGth"] = " 30 "; + Stream stream = httpContext.Response.Body; stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); stream.Write(new byte[10], 0, 10); return stream.WriteAsync(new byte[10], 0, 10); @@ -84,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); } } - + /* TODO: response protocol [Fact] public async Task ResponseBody_Http10WriteNoHeaders_DefaultsConnectionClose() { @@ -104,13 +110,14 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); } } - + */ [Fact] public void ResponseBody_WriteContentLengthNoneWritten_Throws() { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 20 " }; + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.Headers["Content-lenGth"] = " 20 "; return Task.FromResult(0); })) { @@ -123,8 +130,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 20 " }; - env.Get("owin.ResponseBody").Write(new byte[5], 0, 5); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.Headers["Content-lenGth"] = " 20 "; + httpContext.Response.Body.Write(new byte[5], 0, 5); return Task.FromResult(0); })) { @@ -137,9 +145,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 10 " }; - env.Get("owin.ResponseBody").Write(new byte[5], 0, 5); - env.Get("owin.ResponseBody").Write(new byte[6], 0, 6); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.Headers["Content-lenGth"] = " 10 "; + httpContext.Response.Body.Write(new byte[5], 0, 5); + httpContext.Response.Body.Write(new byte[6], 0, 6); return Task.FromResult(0); })) { @@ -156,9 +165,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { try { - env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { " 10 " }; - env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); - env.Get("owin.ResponseBody").Write(new byte[9], 0, 9); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.Headers["Content-lenGth"] = " 10 "; + httpContext.Response.Body.Write(new byte[10], 0, 10); + httpContext.Response.Body.Write(new byte[9], 0, 9); appThrew = false; } catch (Exception) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs index 56b3bb48f4..a4e9126992 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs @@ -10,11 +10,14 @@ using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class ResponseHeaderTests { @@ -44,7 +47,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - var responseHeaders = env.Get>("owin.ResponseHeaders"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var responseInfo = httpContext.GetFeature(); + var responseHeaders = responseInfo.Headers; responseHeaders["Custom-Header1"] = new string[] { "custom1, and custom2", "custom3" }; return Task.FromResult(0); })) @@ -66,7 +71,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - var responseHeaders = env.Get>("owin.ResponseHeaders"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var responseInfo = httpContext.GetFeature(); + var responseHeaders = responseInfo.Headers; responseHeaders["Connection"] = new string[] { "Close" }; return Task.FromResult(0); })) @@ -77,7 +84,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); } } - + /* TODO: [Fact] public async Task ResponseHeaders_SendsHttp10_Gets11Close() { @@ -113,6 +120,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); } } + */ [Fact] public async Task ResponseHeaders_HTTP10Request_Gets11Close() @@ -140,9 +148,11 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - var responseHeaders = env.Get>("owin.ResponseHeaders"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var responseInfo = httpContext.GetFeature(); + var responseHeaders = responseInfo.Headers; responseHeaders["Transfer-Encoding"] = new string[] { "chunked" }; - return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); + return responseInfo.Body.WriteAsync(new byte[10], 0, 10); })) { using (HttpClient client = new HttpClient()) @@ -166,12 +176,14 @@ namespace Microsoft.AspNet.Server.WebListener.Tests using (CreateServer( env => { - var responseHeaders = env.Get>("owin.ResponseHeaders"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var responseInfo = httpContext.GetFeature(); + var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); - var body = env.Get("owin.ResponseBody"); + var body = responseInfo.Body; body.Flush(); - env["owin.ResponseStatusCode"] = 404; // Ignored + responseInfo.StatusCode = 404; // Ignored responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored return Task.FromResult(0); })) @@ -194,12 +206,14 @@ namespace Microsoft.AspNet.Server.WebListener.Tests using (CreateServer( async env => { - var responseHeaders = env.Get>("owin.ResponseHeaders"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var responseInfo = httpContext.GetFeature(); + var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); - var body = env.Get("owin.ResponseBody"); + var body = responseInfo.Body; await body.FlushAsync(); - env["owin.ResponseStatusCode"] = 404; // Ignored + responseInfo.StatusCode = 404; // Ignored responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored })) { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs index d176dc2a1a..18912bbba2 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs @@ -13,12 +13,14 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; - using SendFileFunc = Func; + using AppFunc = Func; public class ResponseSendFileTests { @@ -32,8 +34,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { + /* TODO: IDictionary capabilities = env.Get>("server.Capabilities"); Assert.NotNull(capabilities); @@ -43,14 +47,15 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.NotNull(support); Assert.Equal("Overlapped", support.Get("sendfile.Concurrency")); + */ - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - Assert.NotNull(sendFileAsync); + var sendFile = httpContext.GetFeature(); + Assert.NotNull(sendFile); } catch (Exception ex) { byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); + httpContext.Response.Body.Write(body, 0, body.Length); } return Task.FromResult(0); })) @@ -72,10 +77,11 @@ namespace Microsoft.AspNet.Server.WebListener.Tests bool? appThrew = null; using (CreateServer(env => { - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); try { - sendFileAsync(string.Empty, 0, null, CancellationToken.None).Wait(); + sendFile.SendFileAsync(string.Empty, 0, null, CancellationToken.None).Wait(); appThrew = false; } catch (Exception) @@ -103,8 +109,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -121,8 +128,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + return sendFile.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -139,9 +147,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Transfer-EncodinG"] = new string[] { "CHUNKED" }; - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + httpContext.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; + return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -158,10 +167,11 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Transfer-EncodinG"] = new string[] { "CHUNKED" }; - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None).Wait(); - return sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + httpContext.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; + sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None).Wait(); + return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -178,8 +188,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + return sendFile.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -196,8 +207,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + return sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -210,8 +222,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + return sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -224,8 +237,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -242,9 +256,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { FileLength.ToString() }; - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + httpContext.Response.Headers["Content-lenGth"] = FileLength.ToString(); + return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -262,9 +277,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { "10" }; - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + httpContext.Response.Headers["Content-lenGth"] = "10"; + return sendFile.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -282,9 +298,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env.Get>("owin.ResponseHeaders")["Content-lenGth"] = new string[] { "0" }; - SendFileFunc sendFileAsync = env.Get("sendfile.SendAsync"); - return sendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var sendFile = httpContext.GetFeature(); + httpContext.Response.Headers["Content-lenGth"] = "0"; + return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) { HttpResponseMessage response = await SendRequestAsync(Address); diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs index 537ad8c6c9..ae9562a94d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs @@ -6,13 +6,17 @@ using System; using System.Collections.Generic; +using System.Net; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class ResponseTests { @@ -23,7 +27,8 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - Assert.Equal(200, env["owin.ResponseStatusCode"]); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + Assert.Equal(200, httpContext.Response.StatusCode); return Task.FromResult(0); })) { @@ -40,8 +45,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env["owin.ResponseStatusCode"] = 201; - env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.StatusCode = 201; + // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value return Task.FromResult(0); })) { @@ -58,9 +64,10 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env["owin.ResponseStatusCode"] = 201; - env["owin.ResponseReasonPhrase"] = "CustomReasonPhrase"; - env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.StatusCode = 201; + httpContext.GetFeature().ReasonPhrase = "CustomReasonPhrase"; // TODO? + // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value return Task.FromResult(0); })) { @@ -77,7 +84,8 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - env["owin.ResponseStatusCode"] = 901; + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.StatusCode = 901; return Task.FromResult(0); })) { @@ -89,28 +97,32 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } [Fact] - public void Response_100_Throws() + public async Task Response_100_Throws() { using (CreateServer(env => { - env["owin.ResponseStatusCode"] = 100; + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.StatusCode = 100; return Task.FromResult(0); })) { - Assert.Throws(() => SendRequestAsync(Address).Result); + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(500, (int)response.StatusCode); } } [Fact] - public void Response_0_Throws() + public async Task Response_0_Throws() { using (CreateServer(env => { - env["owin.ResponseStatusCode"] = 0; + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.StatusCode = 0; return Task.FromResult(0); })) { - Assert.Throws(() => SendRequestAsync(Address).Result); + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); } } diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs index 84f76d9a52..f1c5c3e22a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs @@ -13,11 +13,13 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener.Tests { - using AppFunc = Func, Task>; + using AppFunc = Func; public class ServerTests { @@ -41,11 +43,9 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - byte[] body = Encoding.UTF8.GetBytes("Hello World"); - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Content-Length"] = new string[] { body.Length.ToString() }; - env.Get("owin.ResponseBody").Write(body, 0, body.Length); - return Task.FromResult(0); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); })) { string response = await SendRequestAsync(Address); @@ -58,13 +58,11 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { using (CreateServer(env => { - string input = new StreamReader(env.Get("owin.RequestBody")).ReadToEnd(); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + string input = new StreamReader(httpContext.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); - byte[] body = Encoding.UTF8.GetBytes("Hello World"); - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Content-Length"] = new string[] { body.Length.ToString() }; - env.Get("owin.ResponseBody").Write(body, 0, body.Length); - return Task.FromResult(0); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); })) { string response = await SendRequestAsync(Address, "Hello World"); @@ -154,7 +152,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.True(Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(2)), "Timed out"); } } - + /* TODO: [Fact] public async Task Server_ClientDisconnects_CallCancelled() { @@ -204,7 +202,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal(string.Empty, response); } } - + */ private IDisposable CreateServer(AppFunc app) { IDictionary properties = new Dictionary(); diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/project.json b/test/Microsoft.AspNet.Server.WebListener.Test/project.json index b11449f836..13c881b938 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.Test/project.json @@ -1,7 +1,11 @@ { "version" : "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Server.WebListener" : "" + "Microsoft.AspNet.Server.WebListener" : "", + "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", + "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", + "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*" }, "configurations": { "net45": { From da1e6c3e7f9fed69f22f399bfb6563f54e680f57 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 17 Feb 2014 11:57:21 -0800 Subject: [PATCH 005/597] Directly build IPAddress from SocketAddress. --- .../NativeInterop/SocketAddress.cs | 31 +++++++++++++++++++ .../RequestProcessing/Request.cs | 10 +++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs index 9dfdb69ac3..78b52c13c7 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; +using System.Net; using System.Text; namespace Microsoft.AspNet.Server.WebListener @@ -170,6 +171,36 @@ namespace Microsoft.AspNet.Server.WebListener return _hash; } + internal IPAddress GetIPAddress() + { + if (Family == AddressFamily.InterNetworkV6) + { + return GetIpv6Address(); + } + else if (Family == AddressFamily.InterNetwork) + { + return GetIPv4Address(); + } + else + { + return null; + } + } + + private IPAddress GetIpv6Address() + { + Contract.Assert(Size >= IPv6AddressSize); + byte[] bytes = new byte[NumberOfIPv6Labels * 2]; + Array.Copy(_buffer, 8, bytes, 0, NumberOfIPv6Labels * 2); + return new IPAddress(bytes); // TODO: Does scope id matter? + } + + private IPAddress GetIPv4Address() + { + Contract.Assert(Size >= IPv4AddressSize); + return new IPAddress(new byte[] { _buffer[4], _buffer[5], _buffer[6], _buffer[7] }); + } + public override string ToString() { StringBuilder bytes = new StringBuilder(); diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index dcf3100e30..5505e44ef0 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -356,7 +356,7 @@ namespace Microsoft.AspNet.Server.WebListener { if (!_isLocal.HasValue) { - _isLocal = LocalEndPoint.GetIPAddressString().Equals(RemoteEndPoint.GetIPAddressString()); + _isLocal = LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress()); } return _isLocal.Value; } @@ -457,14 +457,14 @@ namespace Microsoft.AspNet.Server.WebListener return _localEndPoint; } } -#if NET45 + public IPAddress RemoteIpAddress { get { if (_remoteIpAddress == null) { - _remoteIpAddress = IPAddress.Parse(RemoteEndPoint.GetIPAddressString()); // TODO: Create directly from bytes + _remoteIpAddress = RemoteEndPoint.GetIPAddress(); } return _remoteIpAddress; } @@ -480,7 +480,7 @@ namespace Microsoft.AspNet.Server.WebListener { if (_localIpAddress == null) { - _localIpAddress = IPAddress.Parse(LocalEndPoint.GetIPAddressString()); // TODO: Create directly from bytes + _localIpAddress = LocalEndPoint.GetIPAddress(); } return _localIpAddress; } @@ -489,7 +489,7 @@ namespace Microsoft.AspNet.Server.WebListener _localIpAddress = value; } } -#endif + public int RemotePort { get From 2dac6756dce4284ddab28dd00b71ee7332c97483 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 17 Feb 2014 12:16:02 -0800 Subject: [PATCH 006/597] Fix json file formatting. --- .../project.json | 16 ++++----- src/Microsoft.AspNet.WebSockets/project.json | 21 ++++++----- .../project.json | 36 +++++++++---------- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index cb109c3392..dda3697555 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,13 +1,13 @@ { "version": "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", - "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*" + "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", + "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*" }, - "compilationOptions" : { "allowUnsafe": true }, - "configurations": { - "net45" : { }, - "k10" : { } - } + "compilationOptions" : { "allowUnsafe": true }, + "configurations": { + "net45" : { }, + "k10" : { } + } } diff --git a/src/Microsoft.AspNet.WebSockets/project.json b/src/Microsoft.AspNet.WebSockets/project.json index 943893dbd2..f7abac917f 100644 --- a/src/Microsoft.AspNet.WebSockets/project.json +++ b/src/Microsoft.AspNet.WebSockets/project.json @@ -1,17 +1,16 @@ { "version": "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*" + "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*" }, - "compilationOptions" : { "allowUnsafe": true }, - "configurations": - { - "net45" : { - "dependencies": { - "Owin": "1.0", - "Microsoft.Owin": "2.1.0" - } - } + "compilationOptions" : { "allowUnsafe": true }, + "configurations": { + "net45" : { + "dependencies": { + "Owin": "1.0", + "Microsoft.Owin": "2.1.0" + } + } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/project.json b/test/Microsoft.AspNet.Server.WebListener.Test/project.json index 13c881b938..48f45fc05b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.Test/project.json @@ -1,20 +1,20 @@ { - "version" : "0.1-alpha-*", - "dependencies": { - "Microsoft.AspNet.Server.WebListener" : "", - "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", - "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", - "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*" - }, - "configurations": { - "net45": { - "dependencies": { - "XUnit": "1.9.2", - "XUnit.Extensions": "1.9.2", - "System.Net.Http": "", - "System.Net.Http.WebRequest": "" - } - } - } + "version" : "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Server.WebListener" : "", + "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", + "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", + "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*" + }, + "configurations": { + "net45": { + "dependencies": { + "XUnit": "1.9.2", + "XUnit.Extensions": "1.9.2", + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" + } + } + } } From ab7e4cb3c85b6748e2b1a8dc16fcaa176356354b Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 20 Feb 2014 13:42:04 -0800 Subject: [PATCH 007/597] Prototype IServerFactory --- .../NativeInterop/SocketAddress.cs | 4 +- .../OwinServerFactory.cs | 108 ---------------- .../RequestProcessing/NilEnvDictionary.cs | 115 ------------------ .../ServerConfiguration.cs | 29 +++++ .../ServerFactory.cs | 83 +++++++++++++ .../fx/AssemblyNeutralAttribute.cs | 10 ++ .../fx/IServerConfiguration.cs | 14 +++ .../fx/IServerFactory.cs | 13 ++ .../AuthenticationTests.cs | 37 ++---- .../DictionaryExtensions.cs | 31 ----- .../HttpsTests.cs | 29 +---- .../RequestBodyTests.cs | 29 +---- .../RequestHeaderTests.cs | 23 +--- .../RequestTests.cs | 58 +++------ .../ResponseBodyTests.cs | 35 ++---- .../ResponseHeaderTests.cs | 41 ++----- .../ResponseSendFileTests.cs | 47 +++---- .../ResponseTests.cs | 32 ++--- .../ServerTests.cs | 53 ++++---- .../Utilities.cs | 50 ++++++++ 20 files changed, 312 insertions(+), 529 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs delete mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NilEnvDictionary.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/ServerConfiguration.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/AssemblyNeutralAttribute.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/IServerConfiguration.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs delete mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/DictionaryExtensions.cs create mode 100644 test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs index 78b52c13c7..26d92e61e0 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs @@ -170,7 +170,7 @@ namespace Microsoft.AspNet.Server.WebListener } return _hash; } - +#if NET45 internal IPAddress GetIPAddress() { if (Family == AddressFamily.InterNetworkV6) @@ -200,7 +200,7 @@ namespace Microsoft.AspNet.Server.WebListener Contract.Assert(Size >= IPv4AddressSize); return new IPAddress(new byte[] { _buffer[4], _buffer[5], _buffer[6], _buffer[7] }); } - +#endif public override string ToString() { StringBuilder bytes = new StringBuilder(); diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs deleted file mode 100644 index fa90780375..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/OwinServerFactory.cs +++ /dev/null @@ -1,108 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- -// Copyright 2011-2012 Katana contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; -using System.Threading.Tasks; - -namespace Microsoft.AspNet.Server.WebListener -{ - using AppFunc = Func; - using LoggerFactoryFunc = Func, bool>>; - - /// - /// Implements the Katana setup pattern for this server. - /// - public static class OwinServerFactory - { - /// - /// Populates the server capabilities. - /// Also included is a configurable instance of the server. - /// - /// - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] - public static void Initialize(IDictionary properties) - { - if (properties == null) - { - throw new ArgumentNullException("properties"); - } - - properties[Constants.VersionKey] = Constants.OwinVersion; - - IDictionary capabilities = - properties.Get>(Constants.ServerCapabilitiesKey) - ?? new Dictionary(); - properties[Constants.ServerCapabilitiesKey] = capabilities; - - // SendFile - capabilities[Constants.SendFileVersionKey] = Constants.SendFileVersion; - IDictionary sendfileSupport = new Dictionary(); - sendfileSupport[Constants.SendFileConcurrencyKey] = Constants.Overlapped; - capabilities[Constants.SendFileSupportKey] = sendfileSupport; - - // Opaque - if (ComNetOS.IsWin8orLater) - { - capabilities[Constants.OpaqueVersionKey] = Constants.OpaqueVersion; - } - - // Directly expose the server for advanced configuration. - properties[typeof(OwinWebListener).FullName] = new OwinWebListener(); - } - - /// - /// Creates a server and starts listening on the given addresses. - /// - /// The application entry point. - /// The configuration. - /// The server. Invoke Dispose to shut down. - [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] - public static IDisposable Create(AppFunc app, IDictionary properties) - { - if (app == null) - { - throw new ArgumentNullException("app"); - } - if (properties == null) - { - throw new ArgumentNullException("properties"); - } - - var addresses = properties.Get>>("host.Addresses") - ?? new List>(); - - OwinWebListener server = properties.Get(typeof(OwinWebListener).FullName) - ?? new OwinWebListener(); - - var capabilities = - properties.Get>(Constants.ServerCapabilitiesKey) - ?? new Dictionary(); - - var loggerFactory = properties.Get(Constants.ServerLoggerFactoryKey); - - server.Start(app, addresses, capabilities, loggerFactory); - return server; - } - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NilEnvDictionary.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NilEnvDictionary.cs deleted file mode 100644 index af6cc6aff5..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NilEnvDictionary.cs +++ /dev/null @@ -1,115 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- -// Copyright 2011-2012 Katana contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Microsoft.AspNet.Server.WebListener -{ - internal class NilEnvDictionary : IDictionary - { - private static readonly string[] EmptyKeys = new string[0]; - private static readonly object[] EmptyValues = new object[0]; - private static readonly IEnumerable> EmptyKeyValuePairs = Enumerable.Empty>(); - - public int Count - { - get { return 0; } - } - - public bool IsReadOnly - { - get { return false; } - } - - public ICollection Keys - { - get { return EmptyKeys; } - } - - public ICollection Values - { - get { return EmptyValues; } - } - - [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "Not Implemented")] - public object this[string key] - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public IEnumerator> GetEnumerator() - { - return EmptyKeyValuePairs.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return EmptyKeyValuePairs.GetEnumerator(); - } - - public void Add(KeyValuePair item) - { - throw new NotImplementedException(); - } - - public void Clear() - { - } - - public bool Contains(KeyValuePair item) - { - return false; - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - } - - public bool Remove(KeyValuePair item) - { - return false; - } - - public bool ContainsKey(string key) - { - return false; - } - - public void Add(string key, object value) - { - throw new NotImplementedException(); - } - - public bool Remove(string key) - { - return false; - } - - public bool TryGetValue(string key, out object value) - { - value = null; - return false; - } - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerConfiguration.cs b/src/Microsoft.AspNet.Server.WebListener/ServerConfiguration.cs new file mode 100644 index 0000000000..a050ec4810 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/ServerConfiguration.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Server; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class ServerConfiguration : IServerConfiguration + { + internal ServerConfiguration() + { + Addresses = new List>(1); + } + + public IList> Addresses + { + get; + internal set; + } + + public object AdvancedConfiguration + { + get; + internal set; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs new file mode 100644 index 0000000000..9a3fa32269 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -0,0 +1,83 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- +// Copyright 2011-2012 Katana contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Server; + +namespace Microsoft.AspNet.Server.WebListener +{ + using AppFunc = Func; + using LoggerFactoryFunc = Func, bool>>; + + /// + /// Implements the Katana setup pattern for this server. + /// + public class ServerFactory : IServerFactory + { + private LoggerFactoryFunc _loggerFactory; + + public ServerFactory() + { + // TODO: Get services from DI, like logger factory. + } + + /// + /// Populates the server capabilities. + /// Also included is a configurable instance of the server. + /// + /// + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] + public IServerConfiguration CreateConfiguration() + { + ServerConfiguration serverConfig = new ServerConfiguration(); + serverConfig.AdvancedConfiguration = new OwinWebListener(); + return serverConfig; + } + + /// + /// Creates a server and starts listening on the given addresses. + /// + /// The application entry point. + /// The configuration. + /// The server. Invoke Dispose to shut down. + public IDisposable Start(IServerConfiguration serverConfig, AppFunc app) + { + if (serverConfig == null) + { + throw new ArgumentNullException("serverConfig"); + } + if (app == null) + { + throw new ArgumentNullException("app"); + } + + OwinWebListener server = (OwinWebListener)serverConfig.AdvancedConfiguration; + + var capabilities = new Dictionary(); + + server.Start(app, serverConfig.Addresses, capabilities, _loggerFactory); + return server; + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/AssemblyNeutralAttribute.cs b/src/Microsoft.AspNet.Server.WebListener/fx/AssemblyNeutralAttribute.cs new file mode 100644 index 0000000000..9f503ddd3b --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/AssemblyNeutralAttribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace Microsoft.Net.Runtime +{ + [AssemblyNeutralAttribute] + [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] + public sealed class AssemblyNeutralAttribute : Attribute + { + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/IServerConfiguration.cs b/src/Microsoft.AspNet.Server.WebListener/fx/IServerConfiguration.cs new file mode 100644 index 0000000000..1eaf850ffd --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/IServerConfiguration.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Net.Runtime; + +namespace Microsoft.AspNet.Hosting.Server +{ + [AssemblyNeutral] + public interface IServerConfiguration + { + IList> Addresses { get; } + object AdvancedConfiguration { get; } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs new file mode 100644 index 0000000000..02f525dff9 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Net.Runtime; + +namespace Microsoft.AspNet.Hosting.Server +{ + [AssemblyNeutral] + public interface IServerFactory + { + IServerConfiguration CreateConfiguration(); + IDisposable Start(IServerConfiguration serverConfig, Func app); + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs index 0259f84f43..24a3587f15 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs @@ -14,7 +14,7 @@ using Microsoft.AspNet.PipelineCore; using Xunit; using Xunit.Extensions; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; @@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | AuthenticationType.Digest | AuthenticationType.Basic)] public async Task AuthTypes_EnabledButNotChalleneged_PassThrough(AuthenticationType authType) { - using (CreateServer(authType, env => + using (Utilities.CreateAuthServer(authType, env => { return Task.FromResult(0); })) @@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [InlineData(AuthenticationType.Basic)] public async Task AuthType_Specify401_ChallengesAdded(AuthenticationType authType) { - using (CreateServer(authType, env => + using (Utilities.CreateAuthServer(authType, env => { new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; return Task.FromResult(0); @@ -64,8 +64,13 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task MultipleAuthTypes_Specify401_ChallengesAdded() { - // TODO: Not implemented - Digest - using (CreateServer(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationType.Basic, env => + using (Utilities.CreateAuthServer( + AuthenticationType.Kerberos + | AuthenticationType.Negotiate + | AuthenticationType.Ntlm + /* | AuthenticationType.Digest TODO: Not implemented */ + | AuthenticationType.Basic, + env => { new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; return Task.FromResult(0); @@ -87,7 +92,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests public async Task AuthTypes_Login_Success(AuthenticationType authType) { int requestCount = 0; - using (CreateServer(authType, env => + using (Utilities.CreateAuthServer(authType, env => { requestCount++; / * // TODO: Expose user as feature. @@ -105,26 +110,6 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } } */ - private IDisposable CreateServer(AuthenticationType authType, AppFunc app) - { - IDictionary properties = new Dictionary(); - OwinServerFactory.Initialize(properties); - OwinWebListener listener = (OwinWebListener)properties[typeof(OwinWebListener).FullName]; - listener.AuthenticationManager.AuthenticationTypes = authType; - - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } private async Task SendRequestAsync(string uri, bool useDefaultCredentials = false) { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/DictionaryExtensions.cs b/test/Microsoft.AspNet.Server.WebListener.Test/DictionaryExtensions.cs deleted file mode 100644 index b999b1fc4f..0000000000 --- a/test/Microsoft.AspNet.Server.WebListener.Test/DictionaryExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace System.Collections.Generic -{ - internal static class DictionaryExtensions - { - internal static string Get(this IDictionary dictionary, string key) - { - string[] values; - if (dictionary.TryGetValue(key, out values)) - { - return string.Join(", ", values); - } - return null; - } - - internal static T Get(this IDictionary dictionary, string key) - { - object values; - if (dictionary.TryGetValue(key, out values)) - { - return (T)values; - } - return default(T); - } - } -} diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs index c2e29eccde..f29b417a1b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs @@ -16,7 +16,7 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; @@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Https_200OK_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpsServer(env => { return Task.FromResult(0); })) @@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Https_SendHelloWorld_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpsServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] body = Encoding.UTF8.GetBytes("Hello World"); @@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Https_EchoHelloWorld_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpsServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); string input = new StreamReader(httpContext.Request.Body).ReadToEnd(); @@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { - using (CreateServer(async env => + using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var tls = httpContext.GetFeature(); @@ -92,7 +92,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Https_ClientCertRequested_ClientCertPresent() { - using (CreateServer(async env => + using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var tls = httpContext.GetFeature(); @@ -108,23 +108,6 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } } - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "https"; - address["host"] = "localhost"; - address["port"] = "9090"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - private async Task SendRequestAsync(string uri, X509Certificate cert = null) { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs index 640d0dc489..59df978897 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs @@ -15,7 +15,7 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; @@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task RequestBody_ReadSync_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; @@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task RequestBody_ReadAync_Success() { - using (CreateServer(async env => + using (Utilities.CreateHttpServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; @@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task RequestBody_ReadBeginEnd_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; @@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests public async Task RequestBody_ReadSyncPartialBody_Success() { StaggardContent content = new StaggardContent(); - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[10]; @@ -101,7 +101,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests public async Task RequestBody_ReadAsyncPartialBody_Success() { StaggardContent content = new StaggardContent(); - using (CreateServer(async env => + using (Utilities.CreateHttpServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[10]; @@ -117,23 +117,6 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } } - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - private Task SendRequestAsync(string uri, string upload) { return SendRequestAsync(uri, new StringContent(upload)); diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs index 9e2828c50d..3ebb24eaca 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs @@ -14,7 +14,7 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; @@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task RequestHeaders_ClientSendsDefaultHeaders_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. @@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task RequestHeaders_ClientSendsCustomHeaders_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; Assert.Equal(4, requestHeaders.Count); @@ -64,23 +64,6 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } } - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs index 11c0ce59d1..7eb5ce5bca 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs @@ -12,12 +12,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; using Xunit.Extensions; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; @@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Request_SimpleGet_Success() { - using (CreateServer(env => + using (Utilities.CreateServer("http", "localhost", "8080", "/basepath", env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -66,7 +67,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests httpContext.Response.Body.Write(body, 0, body.Length); } return Task.FromResult(0); - }, "http", "localhost", "8080", "/basepath")) + })) { string response = await SendRequestAsync(Address + "/basepath/SomePath?SomeQuery"); Assert.Equal(string.Empty, response); @@ -74,16 +75,15 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } [Theory] - [InlineData("http", "localhost", "8080", "/", "http://localhost:8080/", "", "/")] - [InlineData("http", "localhost", "8080", "/basepath/", "http://localhost:8080/basepath", "/basepath", "")] - [InlineData("http", "localhost", "8080", "/basepath/", "http://localhost:8080/basepath/", "/basepath", "/")] - [InlineData("http", "localhost", "8080", "/basepath/", "http://localhost:8080/basepath/subpath", "/basepath", "/subpath")] - [InlineData("http", "localhost", "8080", "/base path/", "http://localhost:8080/base%20path/sub path", "/base path", "/sub path")] - [InlineData("http", "localhost", "8080", "/base葉path/", "http://localhost:8080/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] - public async Task Request_PathSplitting(string scheme, string host, string port, string pathBase, string requestUri, - string expectedPathBase, string expectedPath) + [InlineData("/", "http://localhost:8080/", "", "/")] + [InlineData("/basepath/", "http://localhost:8080/basepath", "/basepath", "")] + [InlineData("/basepath/", "http://localhost:8080/basepath/", "/basepath", "/")] + [InlineData("/basepath/", "http://localhost:8080/basepath/subpath", "/basepath", "/subpath")] + [InlineData("/base path/", "http://localhost:8080/base%20path/sub path", "/base path", "/sub path")] + [InlineData("/base葉path/", "http://localhost:8080/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] + public async Task Request_PathSplitting(string pathBase, string requestUri, string expectedPathBase, string expectedPath) { - using (CreateServer(env => + using (Utilities.CreateServer("http", "localhost", "8080", pathBase, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -92,11 +92,11 @@ namespace Microsoft.AspNet.Server.WebListener.Tests var connectionInfo = httpContext.GetFeature(); // Request Keys - Assert.Equal(scheme, requestInfo.Scheme); + Assert.Equal("http", requestInfo.Scheme); Assert.Equal(expectedPath, requestInfo.Path); Assert.Equal(expectedPathBase, requestInfo.PathBase); Assert.Equal(string.Empty, requestInfo.QueryString); - Assert.Equal(port, connectionInfo.LocalPort.ToString()); + Assert.Equal(8080, connectionInfo.LocalPort); } catch (Exception ex) { @@ -104,7 +104,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests httpContext.Response.Body.Write(body, 0, body.Length); } return Task.FromResult(0); - }, scheme, host, port, pathBase)) + })) { string response = await SendRequestAsync(requestUri); Assert.Equal(string.Empty, response); @@ -148,41 +148,23 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } } - private IDisposable CreateServer(AppFunc app, string scheme, string host, string port, string path) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = scheme; - address["host"] = host; - address["port"] = port; - address["path"] = path; - - return OwinServerFactory.Create(app, properties); - } - private IDisposable CreateServer(AppFunc app) { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; + ServerFactory factory = new ServerFactory(); + IServerConfiguration config = factory.CreateConfiguration(); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { IDictionary address = new Dictionary(); - addresses.Add(address); - address["scheme"] = "http"; address["host"] = "localhost"; address["port"] = "8080"; address["path"] = path; + + config.Addresses.Add(address); } - return OwinServerFactory.Create(app, properties); + return factory.Start(config, app); } private async Task SendRequestAsync(string uri) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs index ddcdc4aa2e..0372b63a39 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs @@ -16,7 +16,7 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; @@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Body.Write(new byte[10], 0, 10); @@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseBody_WriteChunked_Chunked() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Request.Headers["transfeR-Encoding"] = " CHunked "; @@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseBody_WriteContentLength_PassedThrough() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 30 "; @@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseBody_Http10WriteNoHeaders_DefaultsConnectionClose() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { env["owin.ResponseProtocol"] = "HTTP/1.0"; env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); @@ -114,7 +114,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public void ResponseBody_WriteContentLengthNoneWritten_Throws() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 20 "; @@ -128,7 +128,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public void ResponseBody_WriteContentLengthNotEnoughWritten_Throws() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 20 "; @@ -143,7 +143,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public void ResponseBody_WriteContentLengthTooMuchWritten_Throws() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 10 "; @@ -161,7 +161,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { ManualResetEvent waitHandle = new ManualResetEvent(false); bool? appThrew = null; - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { try { @@ -195,23 +195,6 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } } - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs index a4e9126992..25f8b29e62 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs @@ -15,7 +15,7 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; @@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseHeaders_ServerSendsDefaultHeaders_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { return Task.FromResult(0); })) @@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -69,7 +69,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseHeaders_ServerSendsConnectionClose_Closed() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -88,7 +88,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseHeaders_SendsHttp10_Gets11Close() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { env["owin.ResponseProtocol"] = "HTTP/1.0"; return Task.FromResult(0); @@ -105,7 +105,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseHeaders_SendsHttp10WithBody_Gets11Close() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { env["owin.ResponseProtocol"] = "HTTP/1.0"; return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); @@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseHeaders_HTTP10Request_Gets11Close() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { return Task.FromResult(0); })) @@ -146,7 +146,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseHeaders_HTTP10Request_RemovesChunkedHeader() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -173,7 +173,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Headers_FlushSendsHeaders_Success() { - using (CreateServer( + using (Utilities.CreateHttpServer( env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); @@ -183,7 +183,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); var body = responseInfo.Body; body.Flush(); - responseInfo.StatusCode = 404; // Ignored + Assert.Throws(() => responseInfo.StatusCode = 404); responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored return Task.FromResult(0); })) @@ -203,7 +203,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Headers_FlushAsyncSendsHeaders_Success() { - using (CreateServer( + using (Utilities.CreateHttpServer( async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); @@ -213,7 +213,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); var body = responseInfo.Body; await body.FlushAsync(); - responseInfo.StatusCode = 404; // Ignored + Assert.Throws(() => responseInfo.StatusCode = 404); responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored })) { @@ -229,23 +229,6 @@ namespace Microsoft.AspNet.Server.WebListener.Tests } } - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs index 18912bbba2..21ec5eb331 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs @@ -18,7 +18,7 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; @@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_SupportKeys_Present() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests { ManualResetEvent waitHandle = new ManualResetEvent(false); bool? appThrew = null; - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -107,7 +107,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -126,7 +126,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_RelativeFile_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -145,7 +145,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_Chunked_Chunked() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -165,7 +165,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_MultipleChunks_Chunked() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -186,7 +186,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_ChunkedHalfOfFile_Chunked() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -205,7 +205,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_ChunkedOffsetOutOfRange_Throws() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -220,7 +220,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_ChunkedCountOutOfRange_Throws() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -235,7 +235,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_ChunkedCount0_Chunked() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -254,7 +254,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_ContentLength_PassedThrough() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -275,7 +275,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_ContentLengthSpecific_PassedThrough() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -296,7 +296,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task ResponseSendFile_ContentLength0_PassedThrough() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -313,25 +313,6 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); } } - - private IDisposable CreateServer(AppFunc app) - { - IList> addresses = new List>(); - IDictionary properties = new Dictionary(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - OwinServerFactory.Initialize(properties); - - return OwinServerFactory.Create(app, properties); - } private async Task SendRequestAsync(string uri) { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs index ae9562a94d..a9f33067aa 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs @@ -14,9 +14,10 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; + using Microsoft.AspNet.Hosting.Server; public class ResponseTests { @@ -25,7 +26,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Response_ServerSendsDefaultResponse_ServerProvidesStatusCodeAndReasonPhrase() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); Assert.Equal(200, httpContext.Response.StatusCode); @@ -43,7 +44,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Response_ServerSendsSpecificStatus_ServerProvidesReasonPhrase() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 201; @@ -62,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Response_ServerSendsSpecificStatusAndReasonPhrase_PassedThrough() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 201; @@ -82,7 +83,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Response_ServerSendsCustomStatus_NoReasonPhrase() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 901; @@ -99,7 +100,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Response_100_Throws() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 100; @@ -114,7 +115,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Response_0_Throws() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 0; @@ -125,23 +126,6 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); } } - - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } private async Task SendRequestAsync(string uri) { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs index f1c5c3e22a..a8b31ae327 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs @@ -17,9 +17,10 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; + using Microsoft.AspNet.Hosting.Server; public class ServerTests { @@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Server_200OK_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { return Task.FromResult(0); })) @@ -41,7 +42,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Server_SendHelloWorld_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentLength = 11; @@ -56,7 +57,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public async Task Server_EchoHelloWorld_Success() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); string input = new StreamReader(httpContext.Request.Body).ReadToEnd(); @@ -73,7 +74,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests [Fact] public void Server_AppException_ClientReset() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { throw new InvalidOperationException(); })) @@ -94,7 +95,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests int requestCount = 0; TaskCompletionSource tcs = new TaskCompletionSource(); - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { if (Interlocked.Increment(ref requestCount) == requestLimit) { @@ -131,7 +132,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests int requestCount = 0; TaskCompletionSource tcs = new TaskCompletionSource(); - using (CreateServer(async env => + using (Utilities.CreateHttpServer(async env => { if (Interlocked.Increment(ref requestCount) == requestLimit) { @@ -161,7 +162,7 @@ namespace Microsoft.AspNet.Server.WebListener.Tests ManualResetEvent aborted = new ManualResetEvent(false); ManualResetEvent canceled = new ManualResetEvent(false); - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { CancellationToken ct = env.Get("owin.CallCancelled"); Assert.True(ct.CanBeCanceled, "CanBeCanceled"); @@ -185,39 +186,29 @@ namespace Microsoft.AspNet.Server.WebListener.Tests Assert.True(canceled.WaitOne(interval), "canceled"); } } + */ [Fact] public async Task Server_SetQueueLimit_Success() { - using (CreateServer(env => - { - // There's no good way to validate this in code. Just execute it to make sure it doesn't crash. - // Run "netsh http show servicestate" to see the current value - var listener = env.Get("Microsoft.AspNet.Server.WebListener.OwinWebListener"); - listener.SetRequestQueueLimit(1001); - return Task.FromResult(0); - })) - { - string response = await SendRequestAsync(Address); - Assert.Equal(string.Empty, response); - } - } - */ - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - IDictionary address = new Dictionary(); - addresses.Add(address); - address["scheme"] = "http"; address["host"] = "localhost"; address["port"] = "8080"; address["path"] = string.Empty; - return OwinServerFactory.Create(app, properties); + ServerFactory factory = new ServerFactory(); + IServerConfiguration config = factory.CreateConfiguration(); + config.Addresses.Add(address); + + OwinWebListener listener = (OwinWebListener)config.AdvancedConfiguration; + listener.SetRequestQueueLimit(1001); + + using (factory.Start(config, env => Task.FromResult(0))) + { + string response = await SendRequestAsync(Address); + Assert.Equal(string.Empty, response); + } } private async Task SendRequestAsync(string uri) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs new file mode 100644 index 0000000000..280f8e4536 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Server; + +namespace Microsoft.AspNet.Server.WebListener.Test +{ + using AppFunc = Func; + + internal static class Utilities + { + internal static IDisposable CreateHttpServer(AppFunc app) + { + return CreateServer("http", "localhost", "8080", string.Empty, app); + } + + internal static IDisposable CreateHttpsServer(AppFunc app) + { + return CreateServer("https", "localhost", "9090", string.Empty, app); + } + + internal static IDisposable CreateAuthServer(AuthenticationType authType, AppFunc app) + { + return CreateServer("http", "localhost", "8080", string.Empty, authType, app); + } + + internal static IDisposable CreateServer(string scheme, string host, string port, string path, AppFunc app) + { + return CreateServer(scheme, host, port, path, AuthenticationType.None, app); + } + + internal static IDisposable CreateServer(string scheme, string host, string port, string path, AuthenticationType authType, AppFunc app) + { + IDictionary address = new Dictionary(); + address["scheme"] = scheme; + address["host"] = host; + address["port"] = port; + address["path"] = path; + + ServerFactory factory = new ServerFactory(); + IServerConfiguration config = factory.CreateConfiguration(); + config.Addresses.Add(address); + + OwinWebListener listener = (OwinWebListener)config.AdvancedConfiguration; + listener.AuthenticationManager.AuthenticationTypes = authType; + + return factory.Start(config, app); + } + } +} From c6c5dd6fbfc1259e2f1b009ffe979b13be91ee60 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 20 Feb 2014 14:51:31 -0800 Subject: [PATCH 008/597] Re-layer the feature interfaces. --- .../OwinWebListener.cs | 3 +- .../RequestProcessing/FeatureContext.cs | 338 ++++++++++++++++++ .../RequestProcessing/Request.cs | 217 ++--------- .../RequestProcessing/RequestContext.cs | 43 +-- .../RequestProcessing/Response.cs | 41 +-- .../RequestProcessing/ResponseStream.cs | 2 + 6 files changed, 393 insertions(+), 251 deletions(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index 5f7b8c3ffb..4220f1c4fc 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -518,7 +518,8 @@ namespace Microsoft.AspNet.Server.WebListener { // TODO: Make disconnect registration lazy RegisterForDisconnectNotification(requestContext); - await _appFunc(requestContext.Features).SupressContext(); + FeatureContext featureContext = new FeatureContext(requestContext); + await _appFunc(featureContext.Features).SupressContext(); await requestContext.ProcessResponseAsync().SupressContext(); } catch (Exception ex) diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs new file mode 100644 index 0000000000..786256daab --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs @@ -0,0 +1,338 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +#if NET45 +using System.Security.Cryptography.X509Certificates; +#endif +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class FeatureContext : IHttpRequestInformation, IHttpConnection, IHttpResponseInformation, IHttpSendFile +#if NET45 + , IHttpTransportLayerSecurity +#endif + { + private RequestContext _requestContext; + private FeatureCollection _features; + + private Stream _requestBody; + private IDictionary _requestHeaders; + private string _scheme; + private string _httpMethod; + private string _httpProtocolVersion; + private string _query; + private string _pathBase; + private string _path; +#if NET45 + private IPAddress _remoteIpAddress; + private IPAddress _localIpAddress; +#endif + private int? _remotePort; + private int? _localPort; + private bool? _isLocal; +#if NET45 + private X509Certificate _clientCert; +#endif + private Stream _responseStream; + private IDictionary _responseHeaders; + + internal FeatureContext(RequestContext requestContext) + { + _requestContext = requestContext; + _features = new FeatureCollection(); + PopulateFeatures(); + } + + internal IFeatureCollection Features + { + get { return _features; } + } + + private Request Request + { + get { return _requestContext.Request; } + } + + private Response Response + { + get { return _requestContext.Response; } + } + + private void PopulateFeatures() + { + _features.Add(typeof(IHttpRequestInformation), this); + _features.Add(typeof(IHttpConnection), this); + if (Request.IsSecureConnection) + { +#if NET45 + // TODO: Should this feature be conditional? Should we add this for HTTP requests? + _features.Add(typeof(IHttpTransportLayerSecurity), this); +#endif + } + _features.Add(typeof(IHttpResponseInformation), this); + _features.Add(typeof(IHttpSendFile), this); + + // TODO: + // _environment.CallCancelled = _cts.Token; + // _environment.User = _request.User; + // Opaque/WebSockets + // Channel binding + + /* + // Server + _environment.Listener = _server; + _environment.ConnectionId = _request.ConnectionId; + */ + } + +#region IHttpRequestInformation + + Stream IHttpRequestInformation.Body + { + get + { + if (_requestBody == null) + { + _requestBody = Request.Body; + } + return _requestBody; + } + set { _requestBody = value; } + } + + IDictionary IHttpRequestInformation.Headers + { + get + { + if (_requestHeaders == null) + { + _requestHeaders = Request.Headers; + } + return _requestHeaders; + } + set { _requestHeaders = value; } + } + + string IHttpRequestInformation.Method + { + get + { + if (_httpMethod == null) + { + _httpMethod = Request.Method; + } + return _httpMethod; + } + set { _httpMethod = value; } + } + + string IHttpRequestInformation.Path + { + get + { + if (_path == null) + { + _path = Request.Path; + } + return _path; + } + set { _path = value; } + } + + string IHttpRequestInformation.PathBase + { + get + { + if (_pathBase == null) + { + _pathBase = Request.PathBase; + } + return _pathBase; + } + set { _pathBase = value; } + } + + string IHttpRequestInformation.Protocol + { + get + { + if (_httpProtocolVersion == null) + { + _httpProtocolVersion = Request.Protocol; + } + return _httpProtocolVersion; + } + set { _httpProtocolVersion = value; } + } + + string IHttpRequestInformation.QueryString + { + get + { + if (_query == null) + { + _query = Request.QueryString; + } + return _query; + } + set { _query = value; } + } + + string IHttpRequestInformation.Scheme + { + get + { + if (_scheme == null) + { + _scheme = Request.Scheme; + } + return _scheme; + } + set { _scheme = value; } + } +#endregion +#region IHttpConnection + bool IHttpConnection.IsLocal + { + get + { + if (_isLocal == null) + { + _isLocal = Request.IsLocal; + } + return _isLocal.Value; + } + set { _isLocal = value; } + } +#if NET45 + IPAddress IHttpConnection.LocalIpAddress + { + get + { + if (_localIpAddress == null) + { + _localIpAddress = Request.LocalIpAddress; + } + return _localIpAddress; + } + set { _localIpAddress = value; } + } + + IPAddress IHttpConnection.RemoteIpAddress + { + get + { + if (_remoteIpAddress == null) + { + _remoteIpAddress = Request.RemoteIpAddress; + } + return _remoteIpAddress; + } + set { _remoteIpAddress = value; } + } +#endif + int IHttpConnection.LocalPort + { + get + { + if (_localPort == null) + { + _localPort = Request.LocalPort; + } + return _localPort.Value; + } + set { _localPort = value; } + } + + int IHttpConnection.RemotePort + { + get + { + if (_remotePort == null) + { + _remotePort = Request.RemotePort; + } + return _remotePort.Value; + } + set { _remotePort = value; } + } +#endregion +#region IHttpTransportLayerSecurity +#if NET45 + X509Certificate IHttpTransportLayerSecurity.ClientCertificate + { + get + { + if (_clientCert == null) + { + _clientCert = Request.GetClientCertificateAsync().Result; // TODO: Sync; + } + return _clientCert; + } + set { _clientCert = value; } + } + + async Task IHttpTransportLayerSecurity.LoadAsync() + { + if (_clientCert == null) + { + _clientCert = await Request.GetClientCertificateAsync(); + } + } +#endif +#endregion +#region IHttpResponseInformation + Stream IHttpResponseInformation.Body + { + get + { + if (_responseStream == null) + { + _responseStream = Response.Body; + } + return _responseStream; + } + set { _responseStream = value; } + } + + IDictionary IHttpResponseInformation.Headers + { + get + { + if (_responseHeaders == null) + { + _responseHeaders = Response.Headers; + } + return _responseHeaders; + } + set { _responseHeaders = value; } + } + + void IHttpResponseInformation.OnSendingHeaders(Action callback, object state) + { + Response.OnSendingHeaders(callback, state); + } + + string IHttpResponseInformation.ReasonPhrase + { + get { return Response.ReasonPhrase; } + set { Response.ReasonPhrase = value; } + } + + int IHttpResponseInformation.StatusCode + { + get { return Response.StatusCode; } + set { Response.StatusCode = value; } + } +#endregion + Task IHttpSendFile.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) + { + return Response.SendFileAsync(path, offset, length, cancellation); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index 5505e44ef0..0a3a186d98 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -11,17 +11,15 @@ using System.IO; using System.Net; using System.Runtime.InteropServices; #if NET45 -using System.Security.Authentication.ExtendedProtection; using System.Security.Cryptography.X509Certificates; #endif using System.Security.Principal; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.HttpFeature; namespace Microsoft.AspNet.Server.WebListener { - internal sealed class Request : IHttpRequestInformation, IHttpConnection, IHttpTransportLayerSecurity, IDisposable + internal sealed class Request : IDisposable { private RequestContext _requestContext; private NativeRequestContext _nativeRequestContext; @@ -31,11 +29,9 @@ namespace Microsoft.AspNet.Server.WebListener private ulong _contextId; private SslStatus _sslStatus; - private string _scheme; private string _httpMethod; private Version _httpVersion; - private string _httpProtocolVersion; // private Uri _requestUri; private string _rawUrl; @@ -53,17 +49,9 @@ namespace Microsoft.AspNet.Server.WebListener private BoundaryType _contentBoundaryType; private long _contentLength; private Stream _nativeStream; - private Stream _requestStream; private SocketAddress _localEndPoint; private SocketAddress _remoteEndPoint; -#if NET45 - private IPAddress _remoteIpAddress; - private IPAddress _localIpAddress; -#endif - private int? _remotePort; - private int? _localPort; - private bool? _isLocal; private IPrincipal _user; @@ -215,25 +203,6 @@ namespace Microsoft.AspNet.Server.WebListener } } -#if NET45 - X509Certificate IHttpTransportLayerSecurity.ClientCertificate - { - get - { - if (_clientCert == null) - { - // TODO: Sync - ((IHttpTransportLayerSecurity)this).LoadAsync().Wait(); - } - return _clientCert; - } - set - { - _clientCert = value; - } - } -#endif - // TODO: Move this to the constructor, that's where it will be called. internal long ContentLength64 { @@ -270,33 +239,15 @@ namespace Microsoft.AspNet.Server.WebListener public IDictionary Headers { - get - { - return _headers; - } - set - { - if (value == null) - { - throw new ArgumentNullException("value"); - } - _headers = value; - } + get { return _headers; } } public string Method { - get - { - return _httpMethod; - } - set - { - _httpMethod = value; - } + get { return _httpMethod; } } - internal Stream NativeStream + public Stream Body { get { @@ -309,60 +260,25 @@ namespace Microsoft.AspNet.Server.WebListener } } - public Stream Body - { - get - { - if (_requestStream == null) - { - // TODO: Move this to the constructor (or a lazy Env dictionary) - _requestStream = NativeStream; - } - return _requestStream; - } - set - { - _requestStream = value; - } - } - public string PathBase { - get - { - return _pathBase; - } - set - { - _pathBase = value; - } + get { return _pathBase; } } public string Path { - get - { - return _path; - } - set - { - _path = value; - } + get { return _path; } } public bool IsLocal { get { - if (!_isLocal.HasValue) - { - _isLocal = LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress()); - } - return _isLocal.Value; - } - set - { - _isLocal = value; +#if NET45 + return LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress()); +#else + throw new NotImplementedException(); +#endif } } @@ -394,30 +310,19 @@ namespace Microsoft.AspNet.Server.WebListener { get { - if (_httpProtocolVersion == null) + if (_httpVersion.Major == 1) { - if (_httpVersion.Major == 1) + if (_httpVersion.Minor == 1) { - if (_httpVersion.Minor == 1) - { - _httpProtocolVersion = "HTTP/1.1"; - } - else if (_httpVersion.Minor == 0) - { - _httpProtocolVersion = "HTTP/1.0"; - } + return "HTTP/1.1"; } - else + else if (_httpVersion.Minor == 0) { - _httpProtocolVersion = "HTTP/" + _httpVersion.ToString(2); + return "HTTP/1.0"; } } - return _httpProtocolVersion; - } - set - { - // TODO: Set _httpVersion? - _httpProtocolVersion = value; + + return "HTTP/" + _httpVersion.ToString(2); } } @@ -432,7 +337,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal SocketAddress RemoteEndPoint + private SocketAddress RemoteEndPoint { get { @@ -445,7 +350,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal SocketAddress LocalEndPoint + private SocketAddress LocalEndPoint { get { @@ -457,85 +362,30 @@ namespace Microsoft.AspNet.Server.WebListener return _localEndPoint; } } - +#if NET45 public IPAddress RemoteIpAddress { - get - { - if (_remoteIpAddress == null) - { - _remoteIpAddress = RemoteEndPoint.GetIPAddress(); - } - return _remoteIpAddress; - } - set - { - _remoteIpAddress = value; - } + get { return RemoteEndPoint.GetIPAddress(); } } public IPAddress LocalIpAddress { - get - { - if (_localIpAddress == null) - { - _localIpAddress = LocalEndPoint.GetIPAddress(); - } - return _localIpAddress; - } - set - { - _localIpAddress = value; - } + get { return LocalEndPoint.GetIPAddress(); } } - +#endif public int RemotePort { - get - { - if (!_remotePort.HasValue) - { - _remotePort = RemoteEndPoint.GetPort(); - } - return _remotePort.Value; - } - set - { - _remotePort = value; - } + get { return RemoteEndPoint.GetPort(); } } public int LocalPort { - get - { - if (!_localPort.HasValue) - { - _localPort = LocalEndPoint.GetPort(); - } - return _localPort.Value; - } - set - { - _localPort = value; - } + get { return LocalEndPoint.GetPort(); } } public string Scheme { - get - { - if (_scheme == null) - { - _scheme = IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; - } - return _scheme; - } - set - { - _scheme = value; - } + get { return IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; } } /* internal Uri RequestUri @@ -594,21 +444,21 @@ namespace Microsoft.AspNet.Server.WebListener #endif } +#if NET45 // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to // enable this, but it's unclear what Http.Sys would do. - async Task IHttpTransportLayerSecurity.LoadAsync() + public async Task GetClientCertificateAsync() { if (SslStatus == SslStatus.Insecure) { // Non-SSL - return; + return null; } // TODO: Verbose log -#if NET45 if (_clientCert != null) { - return; + return _clientCert; } ClientCertLoader certLoader = new ClientCertLoader(RequestContext); @@ -630,10 +480,9 @@ namespace Microsoft.AspNet.Server.WebListener } throw; } -#else - throw new NotImplementedException(); -#endif + return _clientCert; } +#endif // Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be // disposed. diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs index 934ed1eb87..654772e4ad 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs @@ -8,15 +8,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; -using System.Globalization; -using System.IO; using System.Runtime.InteropServices; -using System.Security.Authentication.ExtendedProtection; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.HttpFeature; namespace Microsoft.AspNet.Server.WebListener { @@ -27,7 +21,6 @@ namespace Microsoft.AspNet.Server.WebListener { private static readonly string[] ZeroContentLength = new[] { "0" }; - private FeatureCollection _features; private OwinWebListener _server; private Request _request; private Response _response; @@ -44,18 +37,9 @@ namespace Microsoft.AspNet.Server.WebListener _request = new Request(this, _memoryBlob); _response = new Response(this); _cts = new CancellationTokenSource(); - - _features = new FeatureCollection(); - PopulateFeatures(); - _request.ReleasePins(); } - internal IFeatureCollection Features - { - get { return _features; } - } - internal Request Request { get @@ -100,31 +84,6 @@ namespace Microsoft.AspNet.Server.WebListener return Request.RequestId; } } - - private void PopulateFeatures() - { - _features.Add(typeof(IHttpRequestInformation), Request); - _features.Add(typeof(IHttpConnection), Request); - if (Request.IsSecureConnection) - { - // TODO: Should this feature be conditional? Should we add this for HTTP requests? - _features.Add(typeof(IHttpTransportLayerSecurity), Request); - } - _features.Add(typeof(IHttpResponseInformation), Response); - _features.Add(typeof(IHttpSendFile), Response); - - // TODO: - // _environment.CallCancelled = _cts.Token; - // _environment.User = _request.User; - // Opaque/WebSockets - // Channel binding - - /* - // Server - _environment.Listener = _server; - _environment.ConnectionId = _request.ConnectionId; - */ - } /* public bool TryGetOpaqueUpgrade(ref Action, OpaqueFunc> value) { @@ -265,7 +224,7 @@ namespace Microsoft.AspNet.Server.WebListener Request.SwitchToOpaqueMode(); Response.SwitchToOpaqueMode(); - opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.NativeStream, Response.NativeStream); + opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.Body, Response.Body); return opaqueEnv; } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs index 9f2ac4807d..4988fd0e30 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs @@ -8,23 +8,19 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -using System.IO; using System.Linq; using System.Runtime.InteropServices; -using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.HttpFeature; namespace Microsoft.AspNet.Server.WebListener { - internal sealed unsafe class Response : IHttpResponseInformation, IHttpSendFile, IDisposable + internal sealed unsafe class Response : IDisposable { private ResponseState _responseState; private IDictionary _headers; private string _reasonPhrase; private ResponseStream _nativeStream; - private Stream _responseStream; private long _contentLength; private BoundaryType _boundaryType; private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE _nativeResponse; @@ -79,17 +75,31 @@ namespace Microsoft.AspNet.Server.WebListener { throw new ArgumentOutOfRangeException("value", value, string.Format(Resources.Exception_InvalidStatusCode, value)); } + CheckResponseStarted(); _nativeResponse.StatusCode = (ushort)value; } } + private void CheckResponseStarted() + { + if (_responseState >= ResponseState.SentHeaders) + { + throw new InvalidOperationException("Headers already sent."); + } + } + public string ReasonPhrase { get { return _reasonPhrase; } - set { _reasonPhrase = value; } + set + { + // TODO: Validate user input for illegal chars, length limit, etc.? + CheckResponseStarted(); + _reasonPhrase = value; + } } - internal ResponseStream NativeStream + internal ResponseStream Body { get { @@ -99,25 +109,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - public Stream Body - { - get - { - if (_responseStream == null) - { - _responseStream = NativeStream; - } - return _responseStream; - } - set - { - _responseStream = value; - } - } - internal string GetReasonPhrase(int statusCode) { - // TODO: Validate user input for illegal chars, length limit, etc.? string reasonPhrase = ReasonPhrase; if (string.IsNullOrWhiteSpace(reasonPhrase)) { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs index 84c29adefe..45c3d698ff 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs @@ -89,6 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener uint statusCode; unsafe { + // TODO: Don't add MoreData flag if content-length == 0? flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; statusCode = _requestContext.Response.SendHeaders(null, null, flags, false); } @@ -120,6 +121,7 @@ namespace Microsoft.AspNet.Server.WebListener // TODO: Real cancellation cancellationToken.ThrowIfCancellationRequested(); + // TODO: Don't add MoreData flag if content-length == 0? flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, null, 0, 0, _requestContext.Response.BoundaryType == BoundaryType.Chunked, false); From c9b60c13e4cc777ff945347a8b5ab2ac89406a15 Mon Sep 17 00:00:00 2001 From: Shih-Ying Hsu Date: Tue, 4 Mar 2014 09:26:35 -0800 Subject: [PATCH 009/597] Worker based request processing. A static number of workers are used to listen to requests Signed-off-by: Shih-Ying Hsu --- .../AwaitableThrottle.cs | 100 ++++++++++++++++++ .../OwinWebListener.cs | 80 +++++++------- .../PumpLimits.cs | 7 +- 3 files changed, 144 insertions(+), 43 deletions(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs new file mode 100644 index 0000000000..dc0baa555f --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + /// + /// Awaitable object that acts like a semaphore. The object would wait if more than maxConcurrent number of clients waits on it + /// + public class AwaitableThrottle + { + private static readonly TaskAwaiter CompletedAwaiter = Task.FromResult(true).GetAwaiter(); + + private int _maxConcurrent; + private readonly object _thislock; + private readonly Queue> _awaiters; + + private int _count; + + /// + /// Constructor + /// + /// maximum number of clients that can wait on this object at the same time + public AwaitableThrottle(int maxConcurrent) + { + _thislock = new object(); + _awaiters = new Queue>(); + _maxConcurrent = maxConcurrent; + } + + /// + /// Maximum amount of clients who can await on this throttle + /// + public int MaxConcurrent + { + get + { + return _maxConcurrent; + } + set + { + // Note: non-thread safe + _maxConcurrent = value; + } + } + + /// + /// Called by framework + /// + public TaskAwaiter GetAwaiter() + { + TaskCompletionSource awaiter; + + lock (_thislock) + { + if (_count < _maxConcurrent) + { + _count++; + return CompletedAwaiter; + } + + awaiter = new TaskCompletionSource(); + _awaiters.Enqueue(awaiter); + } + + return awaiter.Task.GetAwaiter(); + } + + /// + /// Release throttle + /// + public void Release() + { + TaskCompletionSource completion = null; + + lock (_thislock) + { + if (_awaiters.Count > 0) + { + completion = _awaiters.Dequeue(); + } + else + { + _count--; + } + } + + if (completion != null) + { + completion.SetResult(true); + } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index 4220f1c4fc..f9ed3fda72 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -78,9 +78,9 @@ namespace Microsoft.AspNet.Server.WebListener private List _uriPrefixes = new List(); private PumpLimits _pumpLimits; - private int _currentOutstandingAccepts; - private int _currentOutstandingRequests; - private Action _offloadListenForNextRequest; + private int _acceptorCounts; + private Action _processRequest; + private readonly AwaitableThrottle _requestProcessingThrottle; // The native request queue private long? _requestQueueLength; @@ -102,9 +102,10 @@ namespace Microsoft.AspNet.Server.WebListener _authManager = new AuthenticationManager(this); _connectionCancellationTokens = new ConcurrentDictionary(); - _offloadListenForNextRequest = new Action(ListenForNextRequestAsync); + _processRequest = new Action(ProcessRequestAsync); _pumpLimits = new PumpLimits(DefaultMaxAccepts, DefaultMaxRequests); + _requestProcessingThrottle = new AwaitableThrottle(DefaultMaxRequests); } internal enum State @@ -189,16 +190,6 @@ namespace Microsoft.AspNet.Server.WebListener } } - private bool CanAcceptMoreRequests - { - get - { - PumpLimits limits = _pumpLimits; - return (_currentOutstandingAccepts < limits.MaxOutstandingAccepts - && _currentOutstandingRequests < limits.MaxOutstandingRequests - _currentOutstandingAccepts); - } - } - /// /// These are merged as one operation because they should be swapped out atomically. /// This controls how many requests the server attempts to process concurrently. @@ -209,8 +200,20 @@ namespace Microsoft.AspNet.Server.WebListener { _pumpLimits = new PumpLimits(maxAccepts, maxRequests); - // Kick the pump in case we went from zero to non-zero limits. - OffloadListenForNextRequestAsync(); + if (_state == State.Started) + { + ActivateRequestProcessingLimits(); + } + } + + private void ActivateRequestProcessingLimits() + { + _requestProcessingThrottle.MaxConcurrent = _pumpLimits.MaxOutstandingRequests; + + for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++) + { + ProcessRequestsWorker(); + } } /// @@ -454,7 +457,7 @@ namespace Microsoft.AspNet.Server.WebListener SetRequestQueueLimit(); - OffloadListenForNextRequestAsync(); + ActivateRequestProcessingLimits(); } catch (Exception exception) { @@ -468,50 +471,45 @@ namespace Microsoft.AspNet.Server.WebListener } } - // Make sure the next request is processed on another thread as to not recursively - // block the request we just received. - private void OffloadListenForNextRequestAsync() - { - if (IsListening && CanAcceptMoreRequests) - { - Task offloadTask = Task.Run(_offloadListenForNextRequest); - } - } - // The message pump. // When we start listening for the next request on one thread, we may need to be sure that the // completion continues on another thread as to not block the current request processing. // The awaits will manage stack depth for us. - private async void ListenForNextRequestAsync() + private async void ProcessRequestsWorker() { - while (IsListening && CanAcceptMoreRequests) + int workerIndex = Interlocked.Increment(ref _acceptorCounts); + while (IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts) { + await _requestProcessingThrottle; + // Receive a request RequestContext requestContext; - Interlocked.Increment(ref _currentOutstandingAccepts); try { requestContext = await GetContextAsync().SupressContext(); - Interlocked.Decrement(ref _currentOutstandingAccepts); } catch (Exception exception) { LogHelper.LogException(_logger, "ListenForNextRequestAsync", exception); - // Assume the server has stopped. - Interlocked.Decrement(ref _currentOutstandingAccepts); Contract.Assert(!IsListening); return; } - - Interlocked.Increment(ref _currentOutstandingRequests); - OffloadListenForNextRequestAsync(); - await ProcessRequestAsync(requestContext).SupressContext(); - Interlocked.Decrement(ref _currentOutstandingRequests); + try + { + Task.Factory.StartNew(_processRequest, requestContext); + } + catch (Exception ex) + { + LogHelper.LogException(_logger, "ProcessRequestAsync", ex); + _requestProcessingThrottle.Release(); + } } + Interlocked.Decrement(ref _acceptorCounts); } - private async Task ProcessRequestAsync(RequestContext requestContext) + private async void ProcessRequestAsync(object requestContextObj) { + var requestContext = requestContextObj as RequestContext; try { try @@ -543,6 +541,10 @@ namespace Microsoft.AspNet.Server.WebListener requestContext.Abort(); requestContext.Dispose(); } + finally + { + _requestProcessingThrottle.Release(); + } } private void CleanupV2Config() diff --git a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs b/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs index 28b99c11cc..f0adac342a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs +++ b/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Server.WebListener { - internal class PumpLimits + internal struct PumpLimits { internal PumpLimits(int maxAccepts, int maxRequests) { @@ -24,8 +24,7 @@ namespace Microsoft.AspNet.Server.WebListener MaxOutstandingRequests = maxRequests; } - internal int MaxOutstandingAccepts { get; private set; } - - internal int MaxOutstandingRequests { get; private set; } + internal readonly int MaxOutstandingAccepts; + internal readonly int MaxOutstandingRequests; } } From 177b0e87bf8a7f2faa4f51847efde741b43694d0 Mon Sep 17 00:00:00 2001 From: Shih-Ying Hsu Date: Wed, 5 Mar 2014 11:17:16 -0800 Subject: [PATCH 010/597] Few changes according to code review --- src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs | 4 ++-- src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs index dc0baa555f..643041b830 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// +// // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ @@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Server.WebListener /// /// Awaitable object that acts like a semaphore. The object would wait if more than maxConcurrent number of clients waits on it /// - public class AwaitableThrottle + internal class AwaitableThrottle { private static readonly TaskAwaiter CompletedAwaiter = Task.FromResult(true).GetAwaiter(); diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index f9ed3fda72..460c7d9e84 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -500,6 +500,8 @@ namespace Microsoft.AspNet.Server.WebListener } catch (Exception ex) { + // Request processing failed to be queued in threadpool + // Log the error message, release throttle and move on LogHelper.LogException(_logger, "ProcessRequestAsync", ex); _requestProcessingThrottle.Release(); } From 2960c5679dca0bb1c6f4970a2aeba9e61cbf7e92 Mon Sep 17 00:00:00 2001 From: Shih-Ying Hsu Date: Wed, 5 Mar 2014 11:22:32 -0800 Subject: [PATCH 011/597] Comments clean up --- .../AwaitableThrottle.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs index 643041b830..28e12028be 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.Server.WebListener { /// - /// Awaitable object that acts like a semaphore. The object would wait if more than maxConcurrent number of clients waits on it + /// AwaitableThrottle is an awaitable object that acts like a semaphore. The object would wait if more than maxConcurrent number of clients waits on it. /// internal class AwaitableThrottle { @@ -23,10 +23,7 @@ namespace Microsoft.AspNet.Server.WebListener private int _count; - /// - /// Constructor - /// - /// maximum number of clients that can wait on this object at the same time + // Maximum number of clients that can wait on this object at the same time. public AwaitableThrottle(int maxConcurrent) { _thislock = new object(); @@ -34,9 +31,6 @@ namespace Microsoft.AspNet.Server.WebListener _maxConcurrent = maxConcurrent; } - /// - /// Maximum amount of clients who can await on this throttle - /// public int MaxConcurrent { get @@ -50,9 +44,6 @@ namespace Microsoft.AspNet.Server.WebListener } } - /// - /// Called by framework - /// public TaskAwaiter GetAwaiter() { TaskCompletionSource awaiter; @@ -72,9 +63,6 @@ namespace Microsoft.AspNet.Server.WebListener return awaiter.Task.GetAwaiter(); } - /// - /// Release throttle - /// public void Release() { TaskCompletionSource completion = null; From 547a9b6e1389447ea7d9d66a5c5a00ca96c14f7b Mon Sep 17 00:00:00 2001 From: Shih-Ying Hsu Date: Wed, 5 Mar 2014 11:49:17 -0800 Subject: [PATCH 012/597] Added validation and documentations for AwaitableThrottle.MaxConcurrent --- .../AwaitableThrottle.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs index 28e12028be..1a196b10c3 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs @@ -5,6 +5,7 @@ //------------------------------------------------------------------------------ using System.Collections.Generic; +using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; using System.Threading.Tasks; @@ -39,7 +40,13 @@ namespace Microsoft.AspNet.Server.WebListener } set { - // Note: non-thread safe + Contract.Assert(_maxConcurrent >= 0, + "Behavior of this class is undefined for negative value"); + // Note: + // 1. This setter is non-thread safe. We assumed it doesnt need to be for simplicity sake. + // 2. Behavior of this class is not well defined if a negative value is passed in. If it + // is awaited before any Release() is called, the subsequent Relese() would eagerly + // unblock awaiting thread instead of waiting for _count to reach the negative value specified. _maxConcurrent = value; } } From 8ac4bbd6cf7ba1467f659da1f1654751a732b36d Mon Sep 17 00:00:00 2001 From: Shih-Ying Hsu Date: Wed, 5 Mar 2014 12:06:08 -0800 Subject: [PATCH 013/597] further code cleanup --- .../AwaitableThrottle.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs index 1a196b10c3..450930dc76 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs @@ -1,10 +1,4 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; using System.Threading.Tasks; From 38f5793e3de7ea98f5be4150f17b64664493627a Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 7 Mar 2014 12:19:36 -0800 Subject: [PATCH 014/597] Seperate message pump into higher layer. --- .../OwinWebListener.cs | 171 +--------------- .../RequestProcessing/Request.cs | 14 -- .../RequestProcessing/RequestContext.cs | 28 +++ .../ResponseStreamAsyncResult.cs | 2 +- .../ServerFactory.cs | 7 +- .../WebListenerWrapper.cs | 192 ++++++++++++++++++ 6 files changed, 230 insertions(+), 184 deletions(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index 460c7d9e84..dbe4fe4944 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -40,8 +40,6 @@ namespace Microsoft.AspNet.Server.WebListener private static readonly int BindingInfoSize = Marshal.SizeOf(); #endif - private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; - private static readonly int DefaultMaxRequests = Int32.MaxValue; // Win8# 559317 fixed a bug in Http.sys's HttpReceiveClientCertificate method. // Without this fix IOCP callbacks were not being called although ERROR_IO_PENDING was @@ -60,8 +58,6 @@ namespace Microsoft.AspNet.Server.WebListener private readonly ConcurrentDictionary _connectionCancellationTokens; - private AppFunc _appFunc; - private IDictionary _capabilities; private LoggerFunc _logger; private SafeHandle _requestQueueHandle; @@ -77,11 +73,6 @@ namespace Microsoft.AspNet.Server.WebListener private List _uriPrefixes = new List(); - private PumpLimits _pumpLimits; - private int _acceptorCounts; - private Action _processRequest; - private readonly AwaitableThrottle _requestProcessingThrottle; - // The native request queue private long? _requestQueueLength; @@ -101,11 +92,6 @@ namespace Microsoft.AspNet.Server.WebListener _timeoutManager = new TimeoutManager(this); _authManager = new AuthenticationManager(this); _connectionCancellationTokens = new ConcurrentDictionary(); - - _processRequest = new Action(ProcessRequestAsync); - - _pumpLimits = new PumpLimits(DefaultMaxAccepts, DefaultMaxRequests); - _requestProcessingThrottle = new AwaitableThrottle(DefaultMaxRequests); } internal enum State @@ -125,11 +111,6 @@ namespace Microsoft.AspNet.Server.WebListener get { return _uriPrefixes; } } - internal IDictionary Capabilities - { - get { return _capabilities; } - } - internal SafeHandle RequestQueueHandle { get @@ -190,46 +171,6 @@ namespace Microsoft.AspNet.Server.WebListener } } - /// - /// These are merged as one operation because they should be swapped out atomically. - /// This controls how many requests the server attempts to process concurrently. - /// - /// The maximum number of pending accepts. - /// The maximum number of outstanding requests. - public void SetRequestProcessingLimits(int maxAccepts, int maxRequests) - { - _pumpLimits = new PumpLimits(maxAccepts, maxRequests); - - if (_state == State.Started) - { - ActivateRequestProcessingLimits(); - } - } - - private void ActivateRequestProcessingLimits() - { - _requestProcessingThrottle.MaxConcurrent = _pumpLimits.MaxOutstandingRequests; - - for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++) - { - ProcessRequestsWorker(); - } - } - - /// - /// Gets the request processing limits. - /// - /// The maximum number of pending accepts. - /// The maximum number of outstanding requests. - [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "By design")] - [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "By design")] - public void GetRequestProcessingLimits(out int maxAccepts, out int maxRequests) - { - PumpLimits limits = _pumpLimits; - maxAccepts = limits.MaxOutstandingAccepts; - maxRequests = limits.MaxOutstandingRequests; - } - /// /// Sets the maximum number of requests that will be queued up in Http.Sys. /// @@ -392,33 +333,13 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal void Start(AppFunc app, IList> addresses, IDictionary capabilities, LoggerFactoryFunc loggerFactory) + internal void Start() { CheckDisposed(); - // Can't call Start twice - Contract.Assert(_appFunc == null); - Contract.Assert(app != null); - Contract.Assert(addresses != null); - Contract.Assert(capabilities != null); - - _appFunc = app; - _capabilities = capabilities; - _logger = LogHelper.CreateLogger(loggerFactory, typeof(OwinWebListener)); + // TODO: _logger = LogHelper.CreateLogger(loggerFactory, typeof(OwinWebListener)); LogHelper.LogInfo(_logger, "Start"); - foreach (var address in addresses) - { - // Build addresses from parts - var scheme = address.Get("scheme") ?? Constants.HttpScheme; - var host = address.Get("host") ?? "localhost"; - var port = address.Get("port") ?? "5000"; - var path = address.Get("path") ?? string.Empty; - - Prefix prefix = Prefix.Create(scheme, host, port, path); - _uriPrefixes.Add(prefix); - } - // Make sure there are no race conditions between Start/Stop/Abort/Close/Dispose and // calls to SetupV2Config: Start needs to setup all resources (esp. in V2 where besides // the request handle, there is also a server session and a Url group. Abort/Stop must @@ -456,8 +377,6 @@ namespace Microsoft.AspNet.Server.WebListener _state = State.Started; SetRequestQueueLimit(); - - ActivateRequestProcessingLimits(); } catch (Exception exception) { @@ -471,84 +390,6 @@ namespace Microsoft.AspNet.Server.WebListener } } - // The message pump. - // When we start listening for the next request on one thread, we may need to be sure that the - // completion continues on another thread as to not block the current request processing. - // The awaits will manage stack depth for us. - private async void ProcessRequestsWorker() - { - int workerIndex = Interlocked.Increment(ref _acceptorCounts); - while (IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts) - { - await _requestProcessingThrottle; - - // Receive a request - RequestContext requestContext; - try - { - requestContext = await GetContextAsync().SupressContext(); - } - catch (Exception exception) - { - LogHelper.LogException(_logger, "ListenForNextRequestAsync", exception); - Contract.Assert(!IsListening); - return; - } - try - { - Task.Factory.StartNew(_processRequest, requestContext); - } - catch (Exception ex) - { - // Request processing failed to be queued in threadpool - // Log the error message, release throttle and move on - LogHelper.LogException(_logger, "ProcessRequestAsync", ex); - _requestProcessingThrottle.Release(); - } - } - Interlocked.Decrement(ref _acceptorCounts); - } - - private async void ProcessRequestAsync(object requestContextObj) - { - var requestContext = requestContextObj as RequestContext; - try - { - try - { - // TODO: Make disconnect registration lazy - RegisterForDisconnectNotification(requestContext); - FeatureContext featureContext = new FeatureContext(requestContext); - await _appFunc(featureContext.Features).SupressContext(); - await requestContext.ProcessResponseAsync().SupressContext(); - } - catch (Exception ex) - { - LogHelper.LogException(_logger, "ProcessRequestAsync", ex); - if (requestContext.Response.SentHeaders) - { - requestContext.Abort(); - } - else - { - // We haven't sent a response yet, try to send a 500 Internal Server Error - requestContext.SetFatalResponse(); - } - } - requestContext.Dispose(); - } - catch (Exception ex) - { - LogHelper.LogException(_logger, "ProcessRequestAsync", ex); - requestContext.Abort(); - requestContext.Dispose(); - } - finally - { - _requestProcessingThrottle.Release(); - } - } - private void CleanupV2Config() { // If we never setup V2, just return. @@ -829,20 +670,18 @@ namespace Microsoft.AspNet.Server.WebListener return asyncResult.Task; } - private void RegisterForDisconnectNotification(RequestContext requestContext) + internal CancellationToken RegisterForDisconnectNotification(RequestContext requestContext) { try { // Create exactly one CancellationToken per connection. ulong connectionId = requestContext.Request.ConnectionId; - CancellationToken ct = GetConnectionCancellation(connectionId); - requestContext.Request.RegisterForDisconnect(ct); - // TODO: Need a feature equivalent for owin.CallCancelled. - // requestContext.Environment.ConnectionDisconnect = ct; + return GetConnectionCancellation(connectionId); } catch (Win32Exception exception) { LogHelper.LogException(_logger, "RegisterForDisconnectNotification", exception); + return CancellationToken.None; } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index 0a3a186d98..78049af54a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -56,7 +56,6 @@ namespace Microsoft.AspNet.Server.WebListener private IPrincipal _user; private bool _isDisposed = false; - private CancellationTokenRegistration _disconnectRegistration; internal unsafe Request(RequestContext httpContext, NativeRequestContext memoryBlob) { @@ -511,7 +510,6 @@ namespace Microsoft.AspNet.Server.WebListener memoryBlob.Dispose(); _nativeRequestContext = null; } - _disconnectRegistration.Dispose(); if (_nativeStream != null) { _nativeStream.Dispose(); @@ -533,17 +531,5 @@ namespace Microsoft.AspNet.Server.WebListener _nativeStream = new RequestStream(RequestContext); } } - - internal void RegisterForDisconnect(CancellationToken cancellationToken) - { - _disconnectRegistration = cancellationToken.Register(Cancel, this); - } - - private static void Cancel(object obj) - { - Request request = (Request)obj; - // Cancels owin.CallCanceled - request.RequestContext.Abort(); - } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs index 654772e4ad..8c4b8d30f0 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs @@ -28,6 +28,8 @@ namespace Microsoft.AspNet.Server.WebListener private NativeRequestContext _memoryBlob; private OpaqueFunc _opaqueCallback; private bool _disposed; + private CancellationTokenRegistration? _disconnectRegistration; + private CancellationToken? _disconnectToken; internal RequestContext(OwinWebListener httpListener, NativeRequestContext memoryBlob) { @@ -56,6 +58,28 @@ namespace Microsoft.AspNet.Server.WebListener } } + internal CancellationToken DisconnectToken + { + get + { + if (!_disconnectToken.HasValue) + { + _disconnectToken = _server.RegisterForDisconnectNotification(this); + if (_disconnectToken.Value.CanBeCanceled) + { + _disconnectRegistration = _disconnectToken.Value.Register(Cancel, this); + } + } + return _disconnectToken.Value; + } + } + + private static void Cancel(object obj) + { + RequestContext context = (RequestContext)obj; + context.Abort(); + } + internal OwinWebListener Server { get @@ -113,6 +137,10 @@ namespace Microsoft.AspNet.Server.WebListener // TODO: Verbose log try { + if (_disconnectRegistration.HasValue) + { + _disconnectRegistration.Value.Dispose(); + } _response.Dispose(); } finally diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs index ca38ba6355..42b81228f8 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs @@ -117,7 +117,7 @@ namespace Microsoft.AspNet.Server.WebListener _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive. #else - _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, useAsync: true); // Extremely expensive. + _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. #endif #if !NET45 throw new NotImplementedException(); diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 9a3fa32269..fc067472ce 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -74,10 +74,11 @@ namespace Microsoft.AspNet.Server.WebListener OwinWebListener server = (OwinWebListener)serverConfig.AdvancedConfiguration; - var capabilities = new Dictionary(); + // TODO: var capabilities = new Dictionary(); + WebListenerWrapper wrapper = new WebListenerWrapper(server); - server.Start(app, serverConfig.Addresses, capabilities, _loggerFactory); - return server; + wrapper.Start(app, serverConfig.Addresses, _loggerFactory); + return wrapper; } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs new file mode 100644 index 0000000000..3cd482cbba --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Diagnostics; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener +{ + using AppFunc = Func; + using LoggerFactoryFunc = Func, bool>>; + using LoggerFunc = Func, bool>; + using System.Threading; + + public class WebListenerWrapper : IDisposable + { + private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; + private static readonly int DefaultMaxRequests = Int32.MaxValue; + + private OwinWebListener _listener; + private AppFunc _appFunc; + private LoggerFunc _logger; + + private PumpLimits _pumpLimits; + private int _acceptorCounts; + private Action _processRequest; + private readonly AwaitableThrottle _requestProcessingThrottle; + + // TODO: private IDictionary _capabilities; + + internal WebListenerWrapper(OwinWebListener listener) + { + Contract.Assert(listener != null); + _listener = listener; + + _processRequest = new Action(ProcessRequestAsync); + _pumpLimits = new PumpLimits(DefaultMaxAccepts, DefaultMaxRequests); + _requestProcessingThrottle = new AwaitableThrottle(DefaultMaxRequests); + } + + internal void Start(AppFunc app, IList> addresses, LoggerFactoryFunc loggerFactory) + { + // Can't call Start twice + Contract.Assert(_appFunc == null); + + Contract.Assert(app != null); + Contract.Assert(addresses != null); + + _appFunc = app; + _logger = LogHelper.CreateLogger(loggerFactory, typeof(WebListenerWrapper)); + LogHelper.LogInfo(_logger, "Start"); + + foreach (var address in addresses) + { + // Build addresses from parts + var scheme = address.Get("scheme") ?? Constants.HttpScheme; + var host = address.Get("host") ?? "localhost"; + var port = address.Get("port") ?? "5000"; + var path = address.Get("path") ?? string.Empty; + + Prefix prefix = Prefix.Create(scheme, host, port, path); + _listener.UriPrefixes.Add(prefix); + } + + _listener.Start(); + + ActivateRequestProcessingLimits(); + } + + /// + /// These are merged as one operation because they should be swapped out atomically. + /// This controls how many requests the server attempts to process concurrently. + /// + /// The maximum number of pending accepts. + /// The maximum number of outstanding requests. + public void SetRequestProcessingLimits(int maxAccepts, int maxRequests) + { + _pumpLimits = new PumpLimits(maxAccepts, maxRequests); + + if (_listener.IsListening) + { + ActivateRequestProcessingLimits(); + } + } + + private void ActivateRequestProcessingLimits() + { + _requestProcessingThrottle.MaxConcurrent = _pumpLimits.MaxOutstandingRequests; + + for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++) + { + ProcessRequestsWorker(); + } + } + + /// + /// Gets the request processing limits. + /// + /// The maximum number of pending accepts. + /// The maximum number of outstanding requests. + [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "By design")] + [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "By design")] + public void GetRequestProcessingLimits(out int maxAccepts, out int maxRequests) + { + PumpLimits limits = _pumpLimits; + maxAccepts = limits.MaxOutstandingAccepts; + maxRequests = limits.MaxOutstandingRequests; + } + + // The message pump. + // When we start listening for the next request on one thread, we may need to be sure that the + // completion continues on another thread as to not block the current request processing. + // The awaits will manage stack depth for us. + private async void ProcessRequestsWorker() + { + int workerIndex = Interlocked.Increment(ref _acceptorCounts); + while (_listener.IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts) + { + await _requestProcessingThrottle; + + // Receive a request + RequestContext requestContext; + try + { + requestContext = await _listener.GetContextAsync().SupressContext(); + } + catch (Exception exception) + { + LogHelper.LogException(_logger, "ListenForNextRequestAsync", exception); + Contract.Assert(!_listener.IsListening); + return; + } + try + { + Task.Factory.StartNew(_processRequest, requestContext); + } + catch (Exception ex) + { + // Request processing failed to be queued in threadpool + // Log the error message, release throttle and move on + LogHelper.LogException(_logger, "ProcessRequestAsync", ex); + _requestProcessingThrottle.Release(); + } + } + Interlocked.Decrement(ref _acceptorCounts); + } + + private async void ProcessRequestAsync(object requestContextObj) + { + var requestContext = requestContextObj as RequestContext; + try + { + try + { + // TODO: Make disconnect registration lazy + FeatureContext featureContext = new FeatureContext(requestContext); + await _appFunc(featureContext.Features).SupressContext(); + await requestContext.ProcessResponseAsync().SupressContext(); + } + catch (Exception ex) + { + LogHelper.LogException(_logger, "ProcessRequestAsync", ex); + if (requestContext.Response.SentHeaders) + { + requestContext.Abort(); + } + else + { + // We haven't sent a response yet, try to send a 500 Internal Server Error + requestContext.SetFatalResponse(); + } + } + requestContext.Dispose(); + } + catch (Exception ex) + { + LogHelper.LogException(_logger, "ProcessRequestAsync", ex); + requestContext.Abort(); + requestContext.Dispose(); + } + finally + { + _requestProcessingThrottle.Release(); + } + } + + public void Dispose() + { + _listener.Dispose(); + } + } +} From 27d834ae6a9cae17fea7e3c3d3632db7c8ef5948 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sat, 8 Mar 2014 04:14:42 -0800 Subject: [PATCH 015/597] Added required packages for K --- samples/HelloWorld/project.json | 12 ++++- samples/SelfHostServer/packages.config | 8 --- .../packages.config | 4 -- .../project.json | 51 ++++++++++++++----- .../packages.config | 5 -- .../packages.config | 5 -- 6 files changed, 50 insertions(+), 35 deletions(-) delete mode 100644 samples/SelfHostServer/packages.config delete mode 100644 src/Microsoft.AspNet.Security.Windows/packages.config delete mode 100644 src/Microsoft.AspNet.WebSockets/packages.config delete mode 100644 test/Microsoft.AspNet.Security.Windows.Test/packages.config diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 63b0cd1595..032365c3bb 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -5,6 +5,16 @@ }, "configurations": { "net45": { }, - "k10" : { } + "k10" : { + "dependencies": { + "System.Collections": "4.0.0.0", + "System.Console" : "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO" : "4.0.0.0", + "System.Runtime" : "4.0.20.0", + "System.Threading.Tasks": "4.0.0.0", + "System.Text.Encoding": "4.0.10.0" + } + } } } diff --git a/samples/SelfHostServer/packages.config b/samples/SelfHostServer/packages.config deleted file mode 100644 index b452be1749..0000000000 --- a/samples/SelfHostServer/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Windows/packages.config b/src/Microsoft.AspNet.Security.Windows/packages.config deleted file mode 100644 index 7432196421..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index dda3697555..a53dd12983 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,13 +1,40 @@ { - "version": "0.1-alpha-*", - "dependencies": { - "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", - "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*" - }, - "compilationOptions" : { "allowUnsafe": true }, - "configurations": { - "net45" : { }, - "k10" : { } - } -} + "version": "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Abstractions": "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", + "Microsoft.AspNet.FeatureModel": "0.1-alpha-*" + }, + "compilationOptions": { + "allowUnsafe": true + }, + "configurations": { + "net45": {}, + "k10": { + "dependencies": { + "System.Collections": "4.0.0.0", + "System.Collections.Concurrent": "4.0.0.0", + "System.Diagnostics.Contracts": "4.0.0.0", + "System.Diagnostics.Debug": "4.0.10.0", + "System.Diagnostics.Tools": "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO": "4.0.0.0", + "System.IO.FileSystem": "4.0.0.0", + "System.IO.FileSystem.Primitives": "4.0.0.0", + "System.Linq": "4.0.0.0", + "System.Reflection": "4.0.10.0", + "System.Resources.ResourceManager": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "System.Runtime.Extensions": "4.0.10.0", + "System.Runtime.InteropServices": "4.0.10.0", + "System.Security.Principal": "4.0.0.0", + "System.Text.Encoding": "4.0.10.0", + "System.Text.Encoding.Extensions": "4.0.10.0", + "System.Threading": "4.0.0.0", + "System.Threading.Overlapped": "4.0.0.0", + "System.Threading.Tasks": "4.0.0.0", + "System.Threading.ThreadPool": "4.0.10.0" + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/packages.config b/src/Microsoft.AspNet.WebSockets/packages.config deleted file mode 100644 index fb47f58ced..0000000000 --- a/src/Microsoft.AspNet.WebSockets/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNet.Security.Windows.Test/packages.config b/test/Microsoft.AspNet.Security.Windows.Test/packages.config deleted file mode 100644 index 67a23e70da..0000000000 --- a/test/Microsoft.AspNet.Security.Windows.Test/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file From fd510db13c4eb126c4c2c4a2737c5800562bf2f8 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 11 Mar 2014 15:16:50 -0700 Subject: [PATCH 016/597] Remove request limit throttle. Move to middleware later. --- .../AwaitableThrottle.cs | 89 ------------------- .../PumpLimits.cs | 4 +- .../WebListenerWrapper.cs | 25 +----- 3 files changed, 5 insertions(+), 113 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs b/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs deleted file mode 100644 index 450930dc76..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/AwaitableThrottle.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -namespace Microsoft.AspNet.Server.WebListener -{ - /// - /// AwaitableThrottle is an awaitable object that acts like a semaphore. The object would wait if more than maxConcurrent number of clients waits on it. - /// - internal class AwaitableThrottle - { - private static readonly TaskAwaiter CompletedAwaiter = Task.FromResult(true).GetAwaiter(); - - private int _maxConcurrent; - private readonly object _thislock; - private readonly Queue> _awaiters; - - private int _count; - - // Maximum number of clients that can wait on this object at the same time. - public AwaitableThrottle(int maxConcurrent) - { - _thislock = new object(); - _awaiters = new Queue>(); - _maxConcurrent = maxConcurrent; - } - - public int MaxConcurrent - { - get - { - return _maxConcurrent; - } - set - { - Contract.Assert(_maxConcurrent >= 0, - "Behavior of this class is undefined for negative value"); - // Note: - // 1. This setter is non-thread safe. We assumed it doesnt need to be for simplicity sake. - // 2. Behavior of this class is not well defined if a negative value is passed in. If it - // is awaited before any Release() is called, the subsequent Relese() would eagerly - // unblock awaiting thread instead of waiting for _count to reach the negative value specified. - _maxConcurrent = value; - } - } - - public TaskAwaiter GetAwaiter() - { - TaskCompletionSource awaiter; - - lock (_thislock) - { - if (_count < _maxConcurrent) - { - _count++; - return CompletedAwaiter; - } - - awaiter = new TaskCompletionSource(); - _awaiters.Enqueue(awaiter); - } - - return awaiter.Task.GetAwaiter(); - } - - public void Release() - { - TaskCompletionSource completion = null; - - lock (_thislock) - { - if (_awaiters.Count > 0) - { - completion = _awaiters.Dequeue(); - } - else - { - _count--; - } - } - - if (completion != null) - { - completion.SetResult(true); - } - } - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs b/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs index f0adac342a..438de700e8 100644 --- a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs +++ b/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs @@ -18,13 +18,11 @@ namespace Microsoft.AspNet.Server.WebListener { internal struct PumpLimits { - internal PumpLimits(int maxAccepts, int maxRequests) + internal PumpLimits(int maxAccepts) { MaxOutstandingAccepts = maxAccepts; - MaxOutstandingRequests = maxRequests; } internal readonly int MaxOutstandingAccepts; - internal readonly int MaxOutstandingRequests; } } diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs index 3cd482cbba..899a3a6638 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs @@ -15,7 +15,6 @@ namespace Microsoft.AspNet.Server.WebListener public class WebListenerWrapper : IDisposable { private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; - private static readonly int DefaultMaxRequests = Int32.MaxValue; private OwinWebListener _listener; private AppFunc _appFunc; @@ -24,7 +23,6 @@ namespace Microsoft.AspNet.Server.WebListener private PumpLimits _pumpLimits; private int _acceptorCounts; private Action _processRequest; - private readonly AwaitableThrottle _requestProcessingThrottle; // TODO: private IDictionary _capabilities; @@ -34,8 +32,7 @@ namespace Microsoft.AspNet.Server.WebListener _listener = listener; _processRequest = new Action(ProcessRequestAsync); - _pumpLimits = new PumpLimits(DefaultMaxAccepts, DefaultMaxRequests); - _requestProcessingThrottle = new AwaitableThrottle(DefaultMaxRequests); + _pumpLimits = new PumpLimits(DefaultMaxAccepts); } internal void Start(AppFunc app, IList> addresses, LoggerFactoryFunc loggerFactory) @@ -72,10 +69,9 @@ namespace Microsoft.AspNet.Server.WebListener /// This controls how many requests the server attempts to process concurrently. /// /// The maximum number of pending accepts. - /// The maximum number of outstanding requests. - public void SetRequestProcessingLimits(int maxAccepts, int maxRequests) + public void SetRequestProcessingLimits(int maxAccepts) { - _pumpLimits = new PumpLimits(maxAccepts, maxRequests); + _pumpLimits = new PumpLimits(maxAccepts); if (_listener.IsListening) { @@ -85,8 +81,6 @@ namespace Microsoft.AspNet.Server.WebListener private void ActivateRequestProcessingLimits() { - _requestProcessingThrottle.MaxConcurrent = _pumpLimits.MaxOutstandingRequests; - for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++) { ProcessRequestsWorker(); @@ -97,14 +91,11 @@ namespace Microsoft.AspNet.Server.WebListener /// Gets the request processing limits. /// /// The maximum number of pending accepts. - /// The maximum number of outstanding requests. [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "By design")] - [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "By design")] - public void GetRequestProcessingLimits(out int maxAccepts, out int maxRequests) + public void GetRequestProcessingLimits(out int maxAccepts) { PumpLimits limits = _pumpLimits; maxAccepts = limits.MaxOutstandingAccepts; - maxRequests = limits.MaxOutstandingRequests; } // The message pump. @@ -116,8 +107,6 @@ namespace Microsoft.AspNet.Server.WebListener int workerIndex = Interlocked.Increment(ref _acceptorCounts); while (_listener.IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts) { - await _requestProcessingThrottle; - // Receive a request RequestContext requestContext; try @@ -139,7 +128,6 @@ namespace Microsoft.AspNet.Server.WebListener // Request processing failed to be queued in threadpool // Log the error message, release throttle and move on LogHelper.LogException(_logger, "ProcessRequestAsync", ex); - _requestProcessingThrottle.Release(); } } Interlocked.Decrement(ref _acceptorCounts); @@ -152,7 +140,6 @@ namespace Microsoft.AspNet.Server.WebListener { try { - // TODO: Make disconnect registration lazy FeatureContext featureContext = new FeatureContext(requestContext); await _appFunc(featureContext.Features).SupressContext(); await requestContext.ProcessResponseAsync().SupressContext(); @@ -178,10 +165,6 @@ namespace Microsoft.AspNet.Server.WebListener requestContext.Abort(); requestContext.Dispose(); } - finally - { - _requestProcessingThrottle.Release(); - } } public void Dispose() From 55ad9ab17a89b67e217b734127b2451517644ea9 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 12 Mar 2014 08:28:45 -0700 Subject: [PATCH 017/597] Support multi-value response headers. --- .../NativeInterop/UnsafeNativeMethods.cs | 25 ++- .../OwinWebListener.cs | 20 +- .../RequestProcessing/Response.cs | 187 +++++++++--------- .../ResponseHeaderTests.cs | 65 +++++- 4 files changed, 182 insertions(+), 115 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs index 0eb890cf8b..5591fd2068 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs @@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Server.WebListener internal static extern uint HttpReceiveHttpRequest(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_REQUEST* pRequestBuffer, uint requestBufferLength, uint* pBytesReturned, SafeNativeOverlapped pOverlapped); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE* pHttpResponse, void* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); + internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2* pHttpResponse, void* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK* pEntityChunks, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); @@ -495,7 +495,7 @@ namespace Microsoft.AspNet.Server.WebListener { internal HTTP_RESPONSE_INFO_TYPE Type; internal uint Length; - internal void* pInfo; + internal HTTP_MULTIPLE_KNOWN_HEADERS* pInfo; } [StructLayout(LayoutKind.Sequential)] @@ -509,10 +509,31 @@ namespace Microsoft.AspNet.Server.WebListener internal HTTP_RESPONSE_HEADERS Headers; internal ushort EntityChunkCount; internal HTTP_DATA_CHUNK* pEntityChunks; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_V2 + { + internal HTTP_RESPONSE Response_V1; internal ushort ResponseInfoCount; internal HTTP_RESPONSE_INFO* pResponseInfo; } + internal enum HTTP_RESPONSE_INFO_FLAGS : uint + { + None = 0, + PreserveOrder = 1, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_MULTIPLE_KNOWN_HEADERS + { + internal HTTP_RESPONSE_HEADER_ID.Enum HeaderId; + internal HTTP_RESPONSE_INFO_FLAGS Flags; + internal ushort KnownHeaderCount; + internal HTTP_KNOWN_HEADER* KnownHeaders; + } + [StructLayout(LayoutKind.Sequential)] internal struct HTTP_REQUEST_AUTH_INFO { diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index dbe4fe4944..904f7a032e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -767,26 +767,26 @@ namespace Microsoft.AspNet.Server.WebListener private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode) { - UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE(); - httpResponse.Version = new UnsafeNclNativeMethods.HttpApi.HTTP_VERSION(); - httpResponse.Version.MajorVersion = (ushort)1; - httpResponse.Version.MinorVersion = (ushort)1; - httpResponse.StatusCode = (ushort)httpStatusCode; + UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2(); + httpResponse.Response_V1.Version = new UnsafeNclNativeMethods.HttpApi.HTTP_VERSION(); + httpResponse.Response_V1.Version.MajorVersion = (ushort)1; + httpResponse.Response_V1.Version.MinorVersion = (ushort)1; + httpResponse.Response_V1.StatusCode = (ushort)httpStatusCode; string statusDescription = HttpReasonPhrase.Get(httpStatusCode); uint dataWritten = 0; uint statusCode; byte[] byteReason = HeaderEncoding.GetBytes(statusDescription); fixed (byte* pReason = byteReason) { - httpResponse.pReason = (sbyte*)pReason; - httpResponse.ReasonLength = (ushort)byteReason.Length; + httpResponse.Response_V1.pReason = (sbyte*)pReason; + httpResponse.Response_V1.ReasonLength = (ushort)byteReason.Length; byte[] byteContentLength = new byte[] { (byte)'0' }; fixed (byte* pContentLength = byteContentLength) { - (&httpResponse.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength; - (&httpResponse.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; - httpResponse.Headers.UnknownHeaderCount = 0; + (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength; + (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; + httpResponse.Response_V1.Headers.UnknownHeaderCount = 0; statusCode = UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs index 4988fd0e30..1db2216f9c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Server.WebListener private ResponseStream _nativeStream; private long _contentLength; private BoundaryType _boundaryType; - private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE _nativeResponse; + private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 _nativeResponse; private IList, object>> _onSendingHeadersActions; private RequestContext _requestContext; @@ -32,12 +32,12 @@ namespace Microsoft.AspNet.Server.WebListener { // TODO: Verbose log _requestContext = httpContext; - _nativeResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE(); + _nativeResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2(); _headers = new Dictionary(StringComparer.OrdinalIgnoreCase); _boundaryType = BoundaryType.None; - _nativeResponse.StatusCode = (ushort)HttpStatusCode.OK; - _nativeResponse.Version.MajorVersion = 1; - _nativeResponse.Version.MinorVersion = 1; + _nativeResponse.Response_V1.StatusCode = (ushort)HttpStatusCode.OK; + _nativeResponse.Response_V1.Version.MajorVersion = 1; + _nativeResponse.Response_V1.Version.MinorVersion = 1; _responseState = ResponseState.Created; _onSendingHeadersActions = new List, object>>(); } @@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Server.WebListener public int StatusCode { - get { return _nativeResponse.StatusCode; } + get { return _nativeResponse.Response_V1.StatusCode; } set { if (value <= 100 || 999 < value) @@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Server.WebListener throw new ArgumentOutOfRangeException("value", value, string.Format(Resources.Exception_InvalidStatusCode, value)); } CheckResponseStarted(); - _nativeResponse.StatusCode = (ushort)value; + _nativeResponse.Response_V1.StatusCode = (ushort)value; } } @@ -296,7 +296,7 @@ namespace Microsoft.AspNet.Server.WebListener // TODO: Verbose log headers _responseState = ResponseState.SentHeaders; - string reasonPhrase = GetReasonPhrase(_nativeResponse.StatusCode); + string reasonPhrase = GetReasonPhrase(_nativeResponse.Response_V1.StatusCode); /* if (m_BoundaryType==BoundaryType.Raw) { @@ -305,23 +305,23 @@ namespace Microsoft.AspNet.Server.WebListener */ uint statusCode; uint bytesSent; - List pinnedHeaders = SerializeHeaders(ref _nativeResponse.Headers, isOpaqueUpgrade); + List pinnedHeaders = SerializeHeaders(); try { if (pDataChunk != null) { - _nativeResponse.EntityChunkCount = 1; - _nativeResponse.pEntityChunks = pDataChunk; + _nativeResponse.Response_V1.EntityChunkCount = 1; + _nativeResponse.Response_V1.pEntityChunks = pDataChunk; } else if (asyncResult != null && asyncResult.DataChunks != null) { - _nativeResponse.EntityChunkCount = asyncResult.DataChunkCount; - _nativeResponse.pEntityChunks = asyncResult.DataChunks; + _nativeResponse.Response_V1.EntityChunkCount = asyncResult.DataChunkCount; + _nativeResponse.Response_V1.pEntityChunks = asyncResult.DataChunks; } else { - _nativeResponse.EntityChunkCount = 0; - _nativeResponse.pEntityChunks = null; + _nativeResponse.Response_V1.EntityChunkCount = 0; + _nativeResponse.Response_V1.pEntityChunks = null; } if (reasonPhrase.Length > 0) @@ -329,10 +329,10 @@ namespace Microsoft.AspNet.Server.WebListener byte[] reasonPhraseBytes = new byte[HeaderEncoding.GetByteCount(reasonPhrase)]; fixed (byte* pReasonPhrase = reasonPhraseBytes) { - _nativeResponse.ReasonLength = (ushort)reasonPhraseBytes.Length; + _nativeResponse.Response_V1.ReasonLength = (ushort)reasonPhraseBytes.Length; HeaderEncoding.GetBytes(reasonPhrase, 0, reasonPhraseBytes.Length, reasonPhraseBytes, 0); - _nativeResponse.pReason = (sbyte*)pReasonPhrase; - fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE* pResponse = &_nativeResponse) + _nativeResponse.Response_V1.pReason = (sbyte*)pReasonPhrase; + fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2* pResponse = &_nativeResponse) { statusCode = UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( @@ -359,7 +359,7 @@ namespace Microsoft.AspNet.Server.WebListener } else { - fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE* pResponse = &_nativeResponse) + fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2* pResponse = &_nativeResponse) { statusCode = UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( @@ -414,8 +414,8 @@ namespace Microsoft.AspNet.Server.WebListener // Check the response headers to determine the correct keep alive and boundary type. Version responseVersion = GetProtocolVersion(); - _nativeResponse.Version.MajorVersion = (ushort)responseVersion.Major; - _nativeResponse.Version.MinorVersion = (ushort)responseVersion.Minor; + _nativeResponse.Response_V1.Version.MajorVersion = (ushort)responseVersion.Major; + _nativeResponse.Response_V1.Version.MinorVersion = (ushort)responseVersion.Minor; bool keepAlive = responseVersion >= Constants.V1_1; string connectionString = Headers.Get(HttpKnownHeaderNames.Connection); string keepAliveString = Headers.Get(HttpKnownHeaderNames.KeepAlive); @@ -531,10 +531,10 @@ namespace Microsoft.AspNet.Server.WebListener return flags; } - private List SerializeHeaders(ref UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADERS headers, - bool isOpaqueUpgrade) + private List SerializeHeaders() { UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; + UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; List pinnedHeaders; GCHandle gcHandle; /* @@ -553,124 +553,78 @@ namespace Microsoft.AspNet.Server.WebListener byte[] bytes = null; pinnedHeaders = new List(); - //--------------------------------------------------- - // DTS Issue: 609383: - // The Set-Cookie headers are being merged into one. - // There are two issues here. - // 1. When Set-Cookie headers are set through SetCookie method on the ListenerResponse, - // there is code in the SetCookie method and the methods it calls to flatten the Set-Cookie - // values. This blindly concatenates the cookies with a comma delimiter. There could be - // a cookie value that contains comma, but we don't escape it with %XX value - // - // As an alternative users can add the Set-Cookie header through the AddHeader method - // like ListenerResponse.Headers.Add("name", "value") - // That way they can add multiple headers - AND They can format the value like they want it. - // - // 2. Now that the header collection contains multiple Set-Cookie name, value pairs - // you would think the problem would go away. However here is an interesting thing. - // For NameValueCollection, when you add - // "Set-Cookie", "value1" - // "Set-Cookie", "value2" - // The NameValueCollection.Count == 1. Because there is only one key - // NameValueCollection.Get("Set-Cookie") would conveniently take these two values - // concatenate them with a comma like - // value1,value2. - // In order to get individual values, you need to use - // string[] values = NameValueCollection.GetValues("Set-Cookie"); - // - // ------------------------------------------------------------- - // So here is the proposed fix here. - // We must first to loop through all the NameValueCollection keys - // and if the name is a unknown header, we must compute the number of - // values it has. Then, we should allocate that many unknown header array - // elements. - // - // Note that a part of the fix here is to treat Set-Cookie as an unknown header - // - // - //----------------------------------------------------------- int numUnknownHeaders = 0; + int numKnownMultiHeaders = 0; foreach (KeyValuePair headerPair in Headers) { + if (headerPair.Value.Length == 0) + { + // TODO: Have the collection exclude empty headers. + continue; + } // See if this is an unknown header lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); - // TODO: WWW-Authentiate header - // TODO: HTTP_RESPONSE_V2 has a HTTP_MULTIPLE_KNOWN_HEADERS option where you can supply multiple values. - - // TODO: Consider any 'known' header that has multiple values as 'unknown'? - // Treat Set-Cookie as well as Connection header in opaque mode as unknown - if (lookup == (int)HttpSysResponseHeader.SetCookie || - (isOpaqueUpgrade && lookup == (int)HttpSysResponseHeader.Connection)) - { - lookup = -1; - } - if (lookup == -1) { numUnknownHeaders += headerPair.Value.Length; } + else if (headerPair.Value.Length > 1) + { + numKnownMultiHeaders++; + } + // else known single-value header. } try { - fixed (UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER* pKnownHeaders = &headers.KnownHeaders) + fixed (UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER* pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders) { foreach (KeyValuePair headerPair in Headers) { - headerName = headerPair.Key; - lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); - if (lookup == (int)HttpSysResponseHeader.SetCookie || - (isOpaqueUpgrade && lookup == (int)HttpSysResponseHeader.Connection)) + if (headerPair.Value.Length == 0) { - lookup = -1; + // TODO: Have the collection exclude empty headers. + continue; } + headerName = headerPair.Key; + string[] headerValues = headerPair.Value; + lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); if (lookup == -1) { if (unknownHeaders == null) { - //---------------------------------------- - // *** This following comment is no longer true *** - // we waste some memory here (up to 32*41=1312 bytes) but we gain speed - // unknownHeaders = new UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[Headers.Count-index]; - //-------------------------------------------- unknownHeaders = new UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[numUnknownHeaders]; gcHandle = GCHandle.Alloc(unknownHeaders, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - headers.pUnknownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + _nativeResponse.Response_V1.Headers.pUnknownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); } - //---------------------------------------- - // FOR UNKNOWN HEADERS - // ALLOW MULTIPLE HEADERS to be added - //--------------------------------------- - string[] headerValues = headerPair.Value; for (int headerValueIndex = 0; headerValueIndex < headerValues.Length; headerValueIndex++) { // Add Name bytes = new byte[HeaderEncoding.GetByteCount(headerName)]; - unknownHeaders[headers.UnknownHeaderCount].NameLength = (ushort)bytes.Length; + unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].NameLength = (ushort)bytes.Length; HeaderEncoding.GetBytes(headerName, 0, bytes.Length, bytes, 0); gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - unknownHeaders[headers.UnknownHeaderCount].pName = (sbyte*)gcHandle.AddrOfPinnedObject(); + unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pName = (sbyte*)gcHandle.AddrOfPinnedObject(); // Add Value headerValue = headerValues[headerValueIndex]; bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; - unknownHeaders[headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length; + unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length; HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - unknownHeaders[headers.UnknownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); - headers.UnknownHeaderCount++; + unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + _nativeResponse.Response_V1.Headers.UnknownHeaderCount++; } } - else + else if (headerPair.Value.Length == 1) { - string[] headerValues = headerPair.Value; - headerValue = headerValues.Length == 1 ? headerValues[0] : string.Join(", ", headerValues); + headerValue = headerValues[0]; if (headerValue != null) { bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; @@ -681,6 +635,49 @@ namespace Microsoft.AspNet.Server.WebListener pKnownHeaders[lookup].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); } } + else + { + if (knownHeaderInfo == null) + { + knownHeaderInfo = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[numKnownMultiHeaders]; + gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + _nativeResponse.pResponseInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); + } + + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); + + UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); + + header.HeaderId = (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.Enum)lookup; + header.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only. + + UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER[headerValues.Length]; + gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + header.KnownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + + for (int headerValueIndex = 0; headerValueIndex < headerValues.Length; headerValueIndex++) + { + // Add Value + headerValue = headerValues[headerValueIndex]; + bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; + HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); + gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + nativeHeaderValues[header.KnownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + header.KnownHeaderCount++; + } + + // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. + gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + knownHeaderInfo[_nativeResponse.ResponseInfoCount].pInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); + + _nativeResponse.ResponseInfoCount++; + } } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs index 25f8b29e62..59ce482ed5 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs @@ -18,6 +18,7 @@ using Xunit; namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; + using System.Net; public class ResponseHeaderTests { @@ -42,6 +43,54 @@ namespace Microsoft.AspNet.Server.WebListener.Test } } + [Fact] + public async Task ResponseHeaders_ServerSendsSingleValueKnownHeaders_Success() + { + using (Utilities.CreateHttpServer(env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var responseInfo = httpContext.GetFeature(); + var responseHeaders = responseInfo.Headers; + responseHeaders["WWW-Authenticate"] = new string[] { "custom1" }; + return Task.FromResult(0); + })) + { + // HttpClient would merge the headers no matter what + WebRequest request = WebRequest.Create(Address); + HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync(); + Assert.Equal(4, response.Headers.Count); + Assert.Null(response.Headers["Transfer-Encoding"]); + Assert.Equal(0, response.ContentLength); + Assert.NotNull(response.Headers["Date"]); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); + Assert.Equal(new string[] { "custom1" }, response.Headers.GetValues("WWW-Authenticate")); + } + } + + [Fact] + public async Task ResponseHeaders_ServerSendsMultiValueKnownHeaders_Success() + { + using (Utilities.CreateHttpServer(env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var responseInfo = httpContext.GetFeature(); + var responseHeaders = responseInfo.Headers; + responseHeaders["WWW-Authenticate"] = new string[] { "custom1, and custom2", "custom3" }; + return Task.FromResult(0); + })) + { + // HttpClient would merge the headers no matter what + WebRequest request = WebRequest.Create(Address); + HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync(); + Assert.Equal(4, response.Headers.Count); + Assert.Null(response.Headers["Transfer-Encoding"]); + Assert.Equal(0, response.ContentLength); + Assert.NotNull(response.Headers["Date"]); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); + Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); + } + } + [Fact] public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() { @@ -54,15 +103,15 @@ namespace Microsoft.AspNet.Server.WebListener.Test return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); - response.EnsureSuccessStatusCode(); - Assert.Equal(3, response.Headers.Count()); - Assert.False(response.Headers.TransferEncodingChunked.HasValue); - Assert.True(response.Headers.Date.HasValue); - Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + // HttpClient would merge the headers no matter what + WebRequest request = WebRequest.Create(Address); + HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync(); + Assert.Equal(4, response.Headers.Count); + Assert.Null(response.Headers["Transfer-Encoding"]); + Assert.Equal(0, response.ContentLength); + Assert.NotNull(response.Headers["Date"]); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); - Assert.Equal(1, response.Content.Headers.Count()); - Assert.Equal(0, response.Content.Headers.ContentLength); } } From b374c1b7e34df041994678423e3ca4894e1abfcb Mon Sep 17 00:00:00 2001 From: David Fowler Date: Mon, 24 Mar 2014 08:33:00 -0700 Subject: [PATCH 018/597] Updated dependencies to account for new changes to do with safe handles. --- src/Microsoft.AspNet.Server.WebListener/project.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index a53dd12983..4296fd3058 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -26,9 +26,10 @@ "System.Resources.ResourceManager": "4.0.0.0", "System.Runtime": "4.0.20.0", "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.InteropServices": "4.0.10.0", + "System.Runtime.InteropServices": "4.0.20.0", + "System.Runtime.Handles": "4.0.0.0", "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.10.0", + "System.Text.Encoding": "4.0.20.0", "System.Text.Encoding.Extensions": "4.0.10.0", "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", From 9e8032cc8a975bf3e001b3b8f5a1b1d4c247663c Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 19 Mar 2014 11:48:39 -0700 Subject: [PATCH 019/597] Update IServerFactory, ILoggerFactory. --- .../LogHelper.cs | 24 ++++---- .../OwinWebListener.cs | 9 ++- .../Prefix.cs | 47 ++++++++++++++- .../RequestProcessing/RequestContext.cs | 4 +- .../ServerConfiguration.cs | 29 --------- .../ServerFactory.cs | 59 ++++++++++++------- .../WebListenerWrapper.cs | 46 ++++++++------- .../fx/IServerConfiguration.cs | 14 ----- .../fx/IServerFactory.cs | 9 ++- .../project.json | 5 +- .../RequestTests.cs | 14 ++--- .../ServerTests.cs | 17 ++---- .../Utilities.cs | 19 ++---- .../project.json | 5 +- 14 files changed, 154 insertions(+), 147 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/ServerConfiguration.cs delete mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/IServerConfiguration.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs index a6513df571..cc0fc9d4a4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -7,12 +7,10 @@ using System; using System.Diagnostics; using System.Globalization; +using Microsoft.AspNet.Logging; namespace Microsoft.AspNet.Server.WebListener { - using LoggerFactoryFunc = Func, bool>>; - using LoggerFunc = Func, bool>; - internal static class LogHelper { private static readonly Func LogState = @@ -21,17 +19,17 @@ namespace Microsoft.AspNet.Server.WebListener private static readonly Func LogStateAndError = (state, error) => string.Format(CultureInfo.CurrentCulture, "{0}\r\n{1}", state, error); - internal static LoggerFunc CreateLogger(LoggerFactoryFunc factory, Type type) + internal static ILogger CreateLogger(ILoggerFactory factory, Type type) { if (factory == null) { return null; } - return factory(type.FullName); + return factory.Create(type.FullName); } - internal static void LogInfo(LoggerFunc logger, string data) + internal static void LogInfo(ILogger logger, string data) { if (logger == null) { @@ -39,11 +37,11 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger(TraceEventType.Information, 0, data, null, LogState); + logger.WriteInformation(data); } } - internal static void LogVerbose(LoggerFunc logger, string data) + internal static void LogVerbose(ILogger logger, string data) { if (logger == null) { @@ -51,11 +49,11 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger(TraceEventType.Verbose, 0, data, null, LogState); + logger.WriteVerbose(data); } } - internal static void LogException(LoggerFunc logger, string location, Exception exception) + internal static void LogException(ILogger logger, string location, Exception exception) { if (logger == null) { @@ -63,11 +61,11 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger(TraceEventType.Error, 0, location, exception, LogStateAndError); + logger.WriteError(location, exception); } } - internal static void LogError(LoggerFunc logger, string location, string message) + internal static void LogError(ILogger logger, string location, string message) { if (logger == null) { @@ -75,7 +73,7 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger(TraceEventType.Error, 0, location + ": " + message, null, LogState); + logger.WriteError(location + "; " + message); } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index 904f7a032e..28deb59011 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -15,12 +15,11 @@ using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Logging; namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; - using LoggerFactoryFunc = Func, bool>>; - using LoggerFunc = Func, bool>; /// /// An HTTP server wrapping the Http.Sys APIs that accepts requests and passes them on to the given OWIN application. @@ -58,7 +57,7 @@ namespace Microsoft.AspNet.Server.WebListener private readonly ConcurrentDictionary _connectionCancellationTokens; - private LoggerFunc _logger; + private ILogger _logger; private SafeHandle _requestQueueHandle; private volatile State _state; // m_State is set only within lock blocks, but often read outside locks. @@ -101,12 +100,12 @@ namespace Microsoft.AspNet.Server.WebListener Disposed, } - internal LoggerFunc Logger + internal ILogger Logger { get { return _logger; } } - internal List UriPrefixes + public List UriPrefixes { get { return _uriPrefixes; } } diff --git a/src/Microsoft.AspNet.Server.WebListener/Prefix.cs b/src/Microsoft.AspNet.Server.WebListener/Prefix.cs index 08a0fe61c5..a9c7d642d1 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Prefix.cs +++ b/src/Microsoft.AspNet.Server.WebListener/Prefix.cs @@ -9,7 +9,7 @@ using System.Globalization; namespace Microsoft.AspNet.Server.WebListener { - internal class Prefix + public class Prefix { private Prefix(bool isHttps, string scheme, string host, string port, int portValue, string path) { @@ -76,6 +76,51 @@ namespace Microsoft.AspNet.Server.WebListener return new Prefix(isHttps, scheme, host, port, portValue, path); } + public static Prefix Create(string prefix) + { + string scheme = null; + string host = null; + string port = null; + string path = null; + string whole = prefix ?? string.Empty; + + int delimiterStart1 = whole.IndexOf("://", StringComparison.Ordinal); + if (delimiterStart1 < 0) + { + throw new FormatException("Invalid prefix, missing scheme separator: " + prefix); + } + int delimiterEnd1 = delimiterStart1 + "://".Length; + + int delimiterStart3 = whole.IndexOf("/", delimiterEnd1, StringComparison.Ordinal); + if (delimiterStart3 < 0) + { + delimiterStart3 = whole.Length; + } + int delimiterStart2 = whole.LastIndexOf(":", delimiterStart3 - 1, delimiterStart3 - delimiterEnd1, StringComparison.Ordinal); + int delimiterEnd2 = delimiterStart2 + ":".Length; + if (delimiterStart2 < 0) + { + delimiterStart2 = delimiterStart3; + delimiterEnd2 = delimiterStart3; + } + + scheme = whole.Substring(0, delimiterStart1); + string portString = whole.Substring(delimiterEnd2, delimiterStart3 - delimiterEnd2); + int ignored; + if (int.TryParse(portString, NumberStyles.Integer, CultureInfo.InvariantCulture, out ignored)) + { + host = whole.Substring(delimiterEnd1, delimiterStart2 - delimiterEnd1); + port = portString; + } + else + { + host = whole.Substring(delimiterEnd1, delimiterStart3 - delimiterEnd1); + } + path = whole.Substring(delimiterStart3); + + return Prefix.Create(scheme, host, port, path); + } + public bool IsHttps { get; private set; } public string Scheme { get; private set; } public string Host { get; private set; } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs index 8c4b8d30f0..b326432b45 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs @@ -11,10 +11,10 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Logging; namespace Microsoft.AspNet.Server.WebListener { - using LoggerFunc = Func, bool>; using OpaqueFunc = Func, Task>; internal sealed class RequestContext : IDisposable @@ -88,7 +88,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal LoggerFunc Logger + internal ILogger Logger { get { return Server.Logger; } } diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerConfiguration.cs b/src/Microsoft.AspNet.Server.WebListener/ServerConfiguration.cs deleted file mode 100644 index a050ec4810..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/ServerConfiguration.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNet.Hosting.Server; - -namespace Microsoft.AspNet.Server.WebListener -{ - internal class ServerConfiguration : IServerConfiguration - { - internal ServerConfiguration() - { - Addresses = new List>(1); - } - - public IList> Addresses - { - get; - internal set; - } - - public object AdvancedConfiguration - { - get; - internal set; - } - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index fc067472ce..ef06a65e13 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -19,66 +19,81 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Reflection; using System.Threading.Tasks; +using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.ConfigurationModel; using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Logging; namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; - using LoggerFactoryFunc = Func, bool>>; /// - /// Implements the Katana setup pattern for this server. + /// Implements the setup process for this server. /// public class ServerFactory : IServerFactory { - private LoggerFactoryFunc _loggerFactory; + private ILoggerFactory _loggerFactory; - public ServerFactory() + public ServerFactory(ILoggerFactory loggerFactory) { - // TODO: Get services from DI, like logger factory. + _loggerFactory = loggerFactory; } /// - /// Populates the server capabilities. - /// Also included is a configurable instance of the server. + /// Creates a configurable instance of the server. /// /// [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] - public IServerConfiguration CreateConfiguration() + public IServerInformation Initialize(IConfiguration config) { - ServerConfiguration serverConfig = new ServerConfiguration(); - serverConfig.AdvancedConfiguration = new OwinWebListener(); - return serverConfig; + OwinWebListener listener = new OwinWebListener(); + ParseAddresses(config, listener); + return new WebListenerWrapper(listener, _loggerFactory); } /// - /// Creates a server and starts listening on the given addresses. /// - /// The application entry point. - /// The configuration. + /// The per-request application entry point. + /// The value returned /// The server. Invoke Dispose to shut down. - public IDisposable Start(IServerConfiguration serverConfig, AppFunc app) + public IDisposable Start(IServerInformation server, AppFunc app) { - if (serverConfig == null) + if (server == null) { - throw new ArgumentNullException("serverConfig"); + throw new ArgumentNullException("server"); } if (app == null) { throw new ArgumentNullException("app"); } - OwinWebListener server = (OwinWebListener)serverConfig.AdvancedConfiguration; + WebListenerWrapper wrapper = server as WebListenerWrapper; + if (wrapper == null) + { + throw new ArgumentException("server"); + } // TODO: var capabilities = new Dictionary(); - WebListenerWrapper wrapper = new WebListenerWrapper(server); - wrapper.Start(app, serverConfig.Addresses, _loggerFactory); + wrapper.Start(app); return wrapper; } + + private void ParseAddresses(IConfiguration config, OwinWebListener listener) + { + // TODO: Key format? + string urls; + if (config != null && config.TryGet("server.urls", out urls) && !string.IsNullOrEmpty(urls)) + { + foreach (var value in urls.Split(';')) + { + listener.UriPrefixes.Add(Prefix.Create(value)); + } + } + // TODO: look for just a port option? + } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs index 899a3a6638..8f32b84abe 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs @@ -2,23 +2,23 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; -using System.Diagnostics; +using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.Logging; namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; - using LoggerFactoryFunc = Func, bool>>; - using LoggerFunc = Func, bool>; - using System.Threading; - public class WebListenerWrapper : IDisposable + public class WebListenerWrapper : IServerInformation, IDisposable { private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; - private OwinWebListener _listener; + private readonly OwinWebListener _listener; + private readonly ILogger _logger; + private AppFunc _appFunc; - private LoggerFunc _logger; private PumpLimits _pumpLimits; private int _acceptorCounts; @@ -26,39 +26,43 @@ namespace Microsoft.AspNet.Server.WebListener // TODO: private IDictionary _capabilities; - internal WebListenerWrapper(OwinWebListener listener) + internal WebListenerWrapper(OwinWebListener listener, ILoggerFactory loggerFactory) { Contract.Assert(listener != null); _listener = listener; + _logger = LogHelper.CreateLogger(loggerFactory, typeof(WebListenerWrapper)); _processRequest = new Action(ProcessRequestAsync); _pumpLimits = new PumpLimits(DefaultMaxAccepts); } - internal void Start(AppFunc app, IList> addresses, LoggerFactoryFunc loggerFactory) + public OwinWebListener Listener + { + get { return _listener; } + } + + // Microsoft.AspNet.Server.WebListener + public string Name + { + get { return System.Reflection.IntrospectionExtensions.GetTypeInfo(GetType()).Assembly.GetName().Name; } + } + + internal void Start(AppFunc app) { // Can't call Start twice Contract.Assert(_appFunc == null); Contract.Assert(app != null); - Contract.Assert(addresses != null); _appFunc = app; - _logger = LogHelper.CreateLogger(loggerFactory, typeof(WebListenerWrapper)); - LogHelper.LogInfo(_logger, "Start"); - foreach (var address in addresses) + if (_listener.UriPrefixes.Count == 0) { - // Build addresses from parts - var scheme = address.Get("scheme") ?? Constants.HttpScheme; - var host = address.Get("host") ?? "localhost"; - var port = address.Get("port") ?? "5000"; - var path = address.Get("path") ?? string.Empty; - - Prefix prefix = Prefix.Create(scheme, host, port, path); - _listener.UriPrefixes.Add(prefix); + throw new InvalidOperationException("No address prefixes were defined."); } + LogHelper.LogInfo(_logger, "Start"); + _listener.Start(); ActivateRequestProcessingLimits(); diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/IServerConfiguration.cs b/src/Microsoft.AspNet.Server.WebListener/fx/IServerConfiguration.cs deleted file mode 100644 index 1eaf850ffd..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/fx/IServerConfiguration.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.Net.Runtime; - -namespace Microsoft.AspNet.Hosting.Server -{ - [AssemblyNeutral] - public interface IServerConfiguration - { - IList> Addresses { get; } - object AdvancedConfiguration { get; } - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs index 02f525dff9..42495b42f8 100644 --- a/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs @@ -1,4 +1,5 @@ -using System; +/* TODO: Take a temp dependency on Ms.Aspnet.Hosting until AssemblyNeutral gets fixed. +using System; using System.Threading.Tasks; using Microsoft.Net.Runtime; @@ -7,7 +8,9 @@ namespace Microsoft.AspNet.Hosting.Server [AssemblyNeutral] public interface IServerFactory { - IServerConfiguration CreateConfiguration(); - IDisposable Start(IServerConfiguration serverConfig, Func app); + // IServerConfiguration CreateConfiguration(); + // IDisposable Start(IServerConfiguration serverConfig, Func app); + IDisposable Start(Func app); } } +*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 4296fd3058..38ac1dbd11 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -2,8 +2,11 @@ "version": "0.1-alpha-*", "dependencies": { "Microsoft.AspNet.Abstractions": "0.1-alpha-*", + "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", - "Microsoft.AspNet.FeatureModel": "0.1-alpha-*" + "Microsoft.AspNet.FeatureModel": "0.1-alpha-*", + "Microsoft.AspNet.Logging": "0.1-alpha-*", + "Microsoft.AspNet.Hosting": "0.1-alpha-*" }, "compilationOptions": { "allowUnsafe": true diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs index 7eb5ce5bca..7cfe0f4f1a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs @@ -150,21 +150,15 @@ namespace Microsoft.AspNet.Server.WebListener.Test private IDisposable CreateServer(AppFunc app) { - ServerFactory factory = new ServerFactory(); - IServerConfiguration config = factory.CreateConfiguration(); + ServerFactory factory = new ServerFactory(null); + WebListenerWrapper wrapper = (WebListenerWrapper)factory.Initialize(null); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - IDictionary address = new Dictionary(); - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = path; - - config.Addresses.Add(address); + wrapper.Listener.UriPrefixes.Add(Prefix.Create("http", "localhost", "8080", path)); } - return factory.Start(config, app); + return factory.Start(wrapper, app); } private async Task SendRequestAsync(string uri) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs index a8b31ae327..ecbbc5c68a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs @@ -191,20 +191,13 @@ namespace Microsoft.AspNet.Server.WebListener.Test [Fact] public async Task Server_SetQueueLimit_Success() { - IDictionary address = new Dictionary(); - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; + ServerFactory factory = new ServerFactory(null); + WebListenerWrapper wrapper = (WebListenerWrapper)factory.Initialize(null); + wrapper.Listener.UriPrefixes.Add(Prefix.Create("http://localhost:8080")); - ServerFactory factory = new ServerFactory(); - IServerConfiguration config = factory.CreateConfiguration(); - config.Addresses.Add(address); + wrapper.Listener.SetRequestQueueLimit(1001); - OwinWebListener listener = (OwinWebListener)config.AdvancedConfiguration; - listener.SetRequestQueueLimit(1001); - - using (factory.Start(config, env => Task.FromResult(0))) + using (factory.Start(wrapper, env => Task.FromResult(0))) { string response = await SendRequestAsync(Address); Assert.Equal(string.Empty, response); diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs index 280f8e4536..abc80060dd 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Hosting.Server; namespace Microsoft.AspNet.Server.WebListener.Test @@ -31,20 +32,12 @@ namespace Microsoft.AspNet.Server.WebListener.Test internal static IDisposable CreateServer(string scheme, string host, string port, string path, AuthenticationType authType, AppFunc app) { - IDictionary address = new Dictionary(); - address["scheme"] = scheme; - address["host"] = host; - address["port"] = port; - address["path"] = path; + ServerFactory factory = new ServerFactory(null); + WebListenerWrapper wrapper = (WebListenerWrapper)factory.Initialize(null); + wrapper.Listener.UriPrefixes.Add(Prefix.Create(scheme, host, port, path)); + wrapper.Listener.AuthenticationManager.AuthenticationTypes = authType; - ServerFactory factory = new ServerFactory(); - IServerConfiguration config = factory.CreateConfiguration(); - config.Addresses.Add(address); - - OwinWebListener listener = (OwinWebListener)config.AdvancedConfiguration; - listener.AuthenticationManager.AuthenticationTypes = authType; - - return factory.Start(config, app); + return factory.Start(wrapper, app); } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/project.json b/test/Microsoft.AspNet.Server.WebListener.Test/project.json index 48f45fc05b..a2837ddee9 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.Test/project.json @@ -3,9 +3,12 @@ "dependencies": { "Microsoft.AspNet.Server.WebListener" : "", "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", - "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*" + "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*", + "Microsoft.AspNet.Logging": "0.1-alpha-*", + "Microsoft.AspNet.Hosting": "0.1-alpha-*" }, "configurations": { "net45": { From eb278924706716dc1ced2d7502c73a640eecf067 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 20 Mar 2014 11:21:03 -0700 Subject: [PATCH 020/597] Code review cleanup. --- src/Microsoft.AspNet.Server.WebListener/LogHelper.cs | 6 ------ .../ServerFactory.cs | 4 ++-- .../WebListenerWrapper.cs | 3 ++- .../fx/IServerFactory.cs | 10 +++++----- .../RequestTests.cs | 4 ++-- .../ServerTests.cs | 4 ++-- 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs index cc0fc9d4a4..d8b5217859 100644 --- a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -13,12 +13,6 @@ namespace Microsoft.AspNet.Server.WebListener { internal static class LogHelper { - private static readonly Func LogState = - (state, error) => Convert.ToString(state, CultureInfo.CurrentCulture); - - private static readonly Func LogStateAndError = - (state, error) => string.Format(CultureInfo.CurrentCulture, "{0}\r\n{1}", state, error); - internal static ILogger CreateLogger(ILoggerFactory factory, Type type) { if (factory == null) diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index ef06a65e13..2d134135f2 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -47,10 +47,10 @@ namespace Microsoft.AspNet.Server.WebListener /// /// [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] - public IServerInformation Initialize(IConfiguration config) + public IServerInformation Initialize(IConfiguration configuration) { OwinWebListener listener = new OwinWebListener(); - ParseAddresses(config, listener); + ParseAddresses(configuration, listener); return new WebListenerWrapper(listener, _loggerFactory); } diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs index 8f32b84abe..3785978504 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Abstractions; @@ -44,7 +45,7 @@ namespace Microsoft.AspNet.Server.WebListener // Microsoft.AspNet.Server.WebListener public string Name { - get { return System.Reflection.IntrospectionExtensions.GetTypeInfo(GetType()).Assembly.GetName().Name; } + get { return GetType().GetTypeInfo().Assembly.GetName().Name; } } internal void Start(AppFunc app) diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs index 42495b42f8..d428778aad 100644 --- a/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs @@ -1,16 +1,16 @@ /* TODO: Take a temp dependency on Ms.Aspnet.Hosting until AssemblyNeutral gets fixed. using System; using System.Threading.Tasks; -using Microsoft.Net.Runtime; +using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.ConfigurationModel; namespace Microsoft.AspNet.Hosting.Server { - [AssemblyNeutral] + // TODO: [AssemblyNeutral] public interface IServerFactory { - // IServerConfiguration CreateConfiguration(); - // IDisposable Start(IServerConfiguration serverConfig, Func app); - IDisposable Start(Func app); + IServerInformation Initialize(IConfiguration configuration); + IDisposable Start(IServerInformation serverInformation, Func application); } } */ \ No newline at end of file diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs index 7cfe0f4f1a..be4ec471b1 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs @@ -150,8 +150,8 @@ namespace Microsoft.AspNet.Server.WebListener.Test private IDisposable CreateServer(AppFunc app) { - ServerFactory factory = new ServerFactory(null); - WebListenerWrapper wrapper = (WebListenerWrapper)factory.Initialize(null); + var factory = new ServerFactory(null); + var wrapper = (WebListenerWrapper)factory.Initialize(null); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs index ecbbc5c68a..db6497f4b1 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs @@ -191,8 +191,8 @@ namespace Microsoft.AspNet.Server.WebListener.Test [Fact] public async Task Server_SetQueueLimit_Success() { - ServerFactory factory = new ServerFactory(null); - WebListenerWrapper wrapper = (WebListenerWrapper)factory.Initialize(null); + var factory = new ServerFactory(null); + var wrapper = (WebListenerWrapper)factory.Initialize(null); wrapper.Listener.UriPrefixes.Add(Prefix.Create("http://localhost:8080")); wrapper.Listener.SetRequestQueueLimit(1001); From 546af5ddee99ead0f1d667f0034ddb5e5266e8fb Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 24 Mar 2014 09:44:12 -0700 Subject: [PATCH 021/597] Rename Prefix to UrlPrefix. Seperate IServerInformation to its own implementation. --- .../OwinWebListener.cs | 18 +++--- .../PumpLimits.cs | 28 --------- .../RequestProcessing/Request.cs | 2 +- .../ServerFactory.cs | 12 ++-- .../ServerInformation.cs | 37 ++++++++++++ .../{Prefix.cs => UrlPrefix.cs} | 14 ++--- .../WebListenerWrapper.cs | 60 +++++++------------ .../RequestTests.cs | 8 +-- .../ServerTests.cs | 12 ++-- .../Utilities.cs | 10 ++-- 10 files changed, 95 insertions(+), 106 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs create mode 100644 src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs rename src/Microsoft.AspNet.Server.WebListener/{Prefix.cs => UrlPrefix.cs} (91%) diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index 28deb59011..cc76380f53 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener private object _internalLock; - private List _uriPrefixes = new List(); + private List _urlPrefixes = new List(); // The native request queue private long? _requestQueueLength; @@ -105,9 +105,9 @@ namespace Microsoft.AspNet.Server.WebListener get { return _logger; } } - public List UriPrefixes + public List UrlPrefixes { - get { return _uriPrefixes; } + get { return _urlPrefixes; } } internal SafeHandle RequestQueueHandle @@ -247,12 +247,12 @@ namespace Microsoft.AspNet.Server.WebListener { CheckDisposed(); // go through the uri list and unregister for each one of them - if (_uriPrefixes.Count > 0) + if (_urlPrefixes.Count > 0) { LogHelper.LogInfo(_logger, "RemoveAll"); if (_state == State.Started) { - foreach (Prefix registeredPrefix in _uriPrefixes) + foreach (UrlPrefix registeredPrefix in _urlPrefixes) { // ignore possible failures InternalRemovePrefix(registeredPrefix.Whole); @@ -261,7 +261,7 @@ namespace Microsoft.AspNet.Server.WebListener if (clear) { - _uriPrefixes.Clear(); + _urlPrefixes.Clear(); } } } @@ -605,12 +605,12 @@ namespace Microsoft.AspNet.Server.WebListener private void AddAllPrefixes() { // go through the uri list and register for each one of them - if (_uriPrefixes.Count > 0) + if (_urlPrefixes.Count > 0) { - for (int i = 0; i < _uriPrefixes.Count; i++) + for (int i = 0; i < _urlPrefixes.Count; i++) { // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. - Prefix registeredPrefix = _uriPrefixes[i]; + UrlPrefix registeredPrefix = _urlPrefixes[i]; uint statusCode = InternalAddPrefix(registeredPrefix.Whole, i); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { diff --git a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs b/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs deleted file mode 100644 index 438de700e8..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/PumpLimits.cs +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright 2011-2012 Katana contributors -// -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Microsoft.AspNet.Server.WebListener -{ - internal struct PumpLimits - { - internal PumpLimits(int maxAccepts) - { - MaxOutstandingAccepts = maxAccepts; - } - - internal readonly int MaxOutstandingAccepts; - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index 78049af54a..2136b96bae 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } - Prefix prefix = httpContext.Server.UriPrefixes[(int)_contextId]; + UrlPrefix prefix = httpContext.Server.UrlPrefixes[(int)_contextId]; string orriginalPath = RequestPath; // These paths are both unescaped already. diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 2d134135f2..b0d1b819c4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Server.WebListener { OwinWebListener listener = new OwinWebListener(); ParseAddresses(configuration, listener); - return new WebListenerWrapper(listener, _loggerFactory); + return new ServerInformation(new WebListenerWrapper(listener, _loggerFactory)); } /// @@ -70,16 +70,16 @@ namespace Microsoft.AspNet.Server.WebListener throw new ArgumentNullException("app"); } - WebListenerWrapper wrapper = server as WebListenerWrapper; - if (wrapper == null) + var serverInfo = server as ServerInformation; + if (serverInfo == null) { throw new ArgumentException("server"); } // TODO: var capabilities = new Dictionary(); - wrapper.Start(app); - return wrapper; + serverInfo.Wrapper.Start(app); + return serverInfo.Wrapper; } private void ParseAddresses(IConfiguration config, OwinWebListener listener) @@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener { foreach (var value in urls.Split(';')) { - listener.UriPrefixes.Add(Prefix.Create(value)); + listener.UrlPrefixes.Add(UrlPrefix.Create(value)); } } // TODO: look for just a port option? diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs new file mode 100644 index 0000000000..6e514819c4 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using Microsoft.AspNet.Abstractions; + +namespace Microsoft.AspNet.Server.WebListener +{ + public class ServerInformation : IServerInformation + { + private WebListenerWrapper _webListenerWrapper; + + internal ServerInformation(WebListenerWrapper webListenerWrapper) + { + _webListenerWrapper = webListenerWrapper; + } + + internal WebListenerWrapper Wrapper + { + get { return _webListenerWrapper; } + } + + // Microsoft.AspNet.Server.WebListener + public string Name + { + get { return GetType().GetTypeInfo().Assembly.GetName().Name; } + } + + public OwinWebListener Listener + { + get { return _webListenerWrapper.Listener; } + } + + public int MaxAccepts + { + get { return _webListenerWrapper.MaxAccepts; } + set { _webListenerWrapper.MaxAccepts = value; } + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/Prefix.cs b/src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs similarity index 91% rename from src/Microsoft.AspNet.Server.WebListener/Prefix.cs rename to src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs index a9c7d642d1..7a6e36e1ee 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Prefix.cs +++ b/src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// +// // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ @@ -9,9 +9,9 @@ using System.Globalization; namespace Microsoft.AspNet.Server.WebListener { - public class Prefix + public class UrlPrefix { - private Prefix(bool isHttps, string scheme, string host, string port, int portValue, string path) + private UrlPrefix(bool isHttps, string scheme, string host, string port, int portValue, string path) { IsHttps = isHttps; Scheme = scheme; @@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Server.WebListener /// +, *, IPv4, [IPv6], or a dns name. Http.Sys does not permit punycode (xn--), use Unicode instead. /// If empty, the default port for the given scheme will be used (80 or 443). /// Should start and end with a '/', though a missing trailing slash will be added. This value must be un-escaped. - public static Prefix Create(string scheme, string host, string port, string path) + public static UrlPrefix Create(string scheme, string host, string port, string path) { bool isHttps; if (string.Equals(Constants.HttpScheme, scheme, StringComparison.OrdinalIgnoreCase)) @@ -73,10 +73,10 @@ namespace Microsoft.AspNet.Server.WebListener path += "/"; } - return new Prefix(isHttps, scheme, host, port, portValue, path); + return new UrlPrefix(isHttps, scheme, host, port, portValue, path); } - public static Prefix Create(string prefix) + public static UrlPrefix Create(string prefix) { string scheme = null; string host = null; @@ -118,7 +118,7 @@ namespace Microsoft.AspNet.Server.WebListener } path = whole.Substring(delimiterStart3); - return Prefix.Create(scheme, host, port, path); + return UrlPrefix.Create(scheme, host, port, path); } public bool IsHttps { get; private set; } diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs index 3785978504..1986d8d3de 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs @@ -1,18 +1,14 @@ using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; -using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Logging; namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; - public class WebListenerWrapper : IServerInformation, IDisposable + internal class WebListenerWrapper : IDisposable { private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; @@ -21,7 +17,7 @@ namespace Microsoft.AspNet.Server.WebListener private AppFunc _appFunc; - private PumpLimits _pumpLimits; + private int _maxAccepts; private int _acceptorCounts; private Action _processRequest; @@ -34,18 +30,28 @@ namespace Microsoft.AspNet.Server.WebListener _logger = LogHelper.CreateLogger(loggerFactory, typeof(WebListenerWrapper)); _processRequest = new Action(ProcessRequestAsync); - _pumpLimits = new PumpLimits(DefaultMaxAccepts); + _maxAccepts = DefaultMaxAccepts; } - public OwinWebListener Listener + internal OwinWebListener Listener { get { return _listener; } } - // Microsoft.AspNet.Server.WebListener - public string Name + internal int MaxAccepts { - get { return GetType().GetTypeInfo().Assembly.GetName().Name; } + get + { + return _maxAccepts; + } + set + { + _maxAccepts = value; + if (_listener.IsListening) + { + ActivateRequestProcessingLimits(); + } + } } internal void Start(AppFunc app) @@ -57,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener _appFunc = app; - if (_listener.UriPrefixes.Count == 0) + if (_listener.UrlPrefixes.Count == 0) { throw new InvalidOperationException("No address prefixes were defined."); } @@ -69,40 +75,14 @@ namespace Microsoft.AspNet.Server.WebListener ActivateRequestProcessingLimits(); } - /// - /// These are merged as one operation because they should be swapped out atomically. - /// This controls how many requests the server attempts to process concurrently. - /// - /// The maximum number of pending accepts. - public void SetRequestProcessingLimits(int maxAccepts) - { - _pumpLimits = new PumpLimits(maxAccepts); - - if (_listener.IsListening) - { - ActivateRequestProcessingLimits(); - } - } - private void ActivateRequestProcessingLimits() { - for (int i = _acceptorCounts; i < _pumpLimits.MaxOutstandingAccepts; i++) + for (int i = _acceptorCounts; i < MaxAccepts; i++) { ProcessRequestsWorker(); } } - /// - /// Gets the request processing limits. - /// - /// The maximum number of pending accepts. - [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "By design")] - public void GetRequestProcessingLimits(out int maxAccepts) - { - PumpLimits limits = _pumpLimits; - maxAccepts = limits.MaxOutstandingAccepts; - } - // The message pump. // When we start listening for the next request on one thread, we may need to be sure that the // completion continues on another thread as to not block the current request processing. @@ -110,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener private async void ProcessRequestsWorker() { int workerIndex = Interlocked.Increment(ref _acceptorCounts); - while (_listener.IsListening && workerIndex <= _pumpLimits.MaxOutstandingAccepts) + while (_listener.IsListening && workerIndex <= MaxAccepts) { // Receive a request RequestContext requestContext; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs index be4ec471b1..c95292bbcf 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs @@ -150,15 +150,15 @@ namespace Microsoft.AspNet.Server.WebListener.Test private IDisposable CreateServer(AppFunc app) { - var factory = new ServerFactory(null); - var wrapper = (WebListenerWrapper)factory.Initialize(null); + var factory = new ServerFactory(loggerFactory: null); + var serverInfo = (ServerInformation)factory.Initialize(configuration: null); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - wrapper.Listener.UriPrefixes.Add(Prefix.Create("http", "localhost", "8080", path)); + serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create("http", "localhost", "8080", path)); } - return factory.Start(wrapper, app); + return factory.Start(serverInfo, app); } private async Task SendRequestAsync(string uri) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs index db6497f4b1..c3632fa4c3 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs @@ -116,7 +116,7 @@ namespace Microsoft.AspNet.Server.WebListener.Test requestTasks.Add(requestTask); } - bool success = Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(5)); + bool success = Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(10)); if (!success) { Console.WriteLine(); @@ -191,13 +191,13 @@ namespace Microsoft.AspNet.Server.WebListener.Test [Fact] public async Task Server_SetQueueLimit_Success() { - var factory = new ServerFactory(null); - var wrapper = (WebListenerWrapper)factory.Initialize(null); - wrapper.Listener.UriPrefixes.Add(Prefix.Create("http://localhost:8080")); + var factory = new ServerFactory(loggerFactory: null); + var serverInfo = (ServerInformation)factory.Initialize(configuration: null); + serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create("http://localhost:8080")); - wrapper.Listener.SetRequestQueueLimit(1001); + serverInfo.Listener.SetRequestQueueLimit(1001); - using (factory.Start(wrapper, env => Task.FromResult(0))) + using (factory.Start(serverInfo, env => Task.FromResult(0))) { string response = await SendRequestAsync(Address); Assert.Equal(string.Empty, response); diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs index abc80060dd..eba2edfd9e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs @@ -32,12 +32,12 @@ namespace Microsoft.AspNet.Server.WebListener.Test internal static IDisposable CreateServer(string scheme, string host, string port, string path, AuthenticationType authType, AppFunc app) { - ServerFactory factory = new ServerFactory(null); - WebListenerWrapper wrapper = (WebListenerWrapper)factory.Initialize(null); - wrapper.Listener.UriPrefixes.Add(Prefix.Create(scheme, host, port, path)); - wrapper.Listener.AuthenticationManager.AuthenticationTypes = authType; + var factory = new ServerFactory(loggerFactory: null); + var serverInfo = (ServerInformation)factory.Initialize(configuration: null); + serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); + serverInfo.Listener.AuthenticationManager.AuthenticationTypes = authType; - return factory.Start(wrapper, app); + return factory.Start(serverInfo, app); } } } From aed5b9a1c99c9a04fbb97adc8b4636e8fe41d6d3 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 25 Mar 2014 15:42:50 -0700 Subject: [PATCH 022/597] Convert tests to K test. --- .../AuthenticationTests.cs | 1 - .../HttpsTests.cs | 13 ++++------- .../RequestTests.cs | 1 - .../ResponseSendFileTests.cs | 15 ++++++++---- .../Utilities.cs | 3 +++ .../project.json | 23 ++++++++++++------- 6 files changed, 33 insertions(+), 23 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs index 24a3587f15..9f8887a5c8 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs @@ -12,7 +12,6 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; using Xunit; -using Xunit.Extensions; namespace Microsoft.AspNet.Server.WebListener.Test { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs index f29b417a1b..d96effc06c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs @@ -5,7 +5,6 @@ // ----------------------------------------------------------------------- using System; -using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Security.Cryptography.X509Certificates; @@ -18,13 +17,11 @@ using Xunit; namespace Microsoft.AspNet.Server.WebListener.Test { - using AppFunc = Func; - public class HttpsTests { private const string Address = "https://localhost:9090/"; - [Fact] + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_200OK_Success() { using (Utilities.CreateHttpsServer(env => @@ -37,7 +34,7 @@ namespace Microsoft.AspNet.Server.WebListener.Test } } - [Fact] + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_SendHelloWorld_Success() { using (Utilities.CreateHttpsServer(env => @@ -53,7 +50,7 @@ namespace Microsoft.AspNet.Server.WebListener.Test } } - [Fact] + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_EchoHelloWorld_Success() { using (Utilities.CreateHttpsServer(env => @@ -72,7 +69,7 @@ namespace Microsoft.AspNet.Server.WebListener.Test } } - [Fact] + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { using (Utilities.CreateHttpsServer(async env => @@ -89,7 +86,7 @@ namespace Microsoft.AspNet.Server.WebListener.Test } } - [Fact] + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertRequested_ClientCertPresent() { using (Utilities.CreateHttpsServer(async env => diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs index c95292bbcf..dcfa78eab3 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs @@ -16,7 +16,6 @@ using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -using Xunit.Extensions; namespace Microsoft.AspNet.Server.WebListener.Test { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs index 21ec5eb331..19d790fffa 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs @@ -20,15 +20,20 @@ using Xunit; namespace Microsoft.AspNet.Server.WebListener.Test { - using AppFunc = Func; - public class ResponseSendFileTests { private const string Address = "http://localhost:8080/"; - private static readonly string AbsoluteFilePath = Environment.CurrentDirectory + "\\Microsoft.AspNet.Server.WebListener.dll"; - private static readonly string RelativeFilePath = "Microsoft.AspNet.Server.WebListener.dll"; - private static readonly long FileLength = new FileInfo(AbsoluteFilePath).Length; + private readonly string AbsoluteFilePath; + private readonly string RelativeFilePath; + private readonly long FileLength; + public ResponseSendFileTests() + { + AbsoluteFilePath = Directory.GetFiles(Environment.CurrentDirectory).First(); + RelativeFilePath = Path.GetFileName(AbsoluteFilePath); + FileLength = new FileInfo(AbsoluteFilePath).Length; + } + [Fact] public async Task ResponseSendFile_SupportKeys_Present() { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs index eba2edfd9e..adacfdf832 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs @@ -4,6 +4,9 @@ using System.Threading.Tasks; using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Hosting.Server; +// These tests can't run in parallel because they all use the same port. +[assembly: Xunit.CollectionBehaviorAttribute(Xunit.CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] + namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/project.json b/test/Microsoft.AspNet.Server.WebListener.Test/project.json index a2837ddee9..76202da8df 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.Test/project.json @@ -1,6 +1,14 @@ { "version" : "0.1-alpha-*", + "commands": { + "test": "Xunit.KRunner" + }, "dependencies": { + "Xunit.KRunner": "0.1-alpha-*", + "xunit.abstractions": "2.0.0-aspnet-*", + "xunit.assert": "2.0.0-aspnet-*", + "xunit.core": "2.0.0-aspnet-*", + "xunit.execution": "2.0.0-aspnet-*", "Microsoft.AspNet.Server.WebListener" : "", "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", @@ -11,13 +19,12 @@ "Microsoft.AspNet.Hosting": "0.1-alpha-*" }, "configurations": { - "net45": { - "dependencies": { - "XUnit": "1.9.2", - "XUnit.Extensions": "1.9.2", - "System.Net.Http": "", - "System.Net.Http.WebRequest": "" - } - } + "net45": { + "dependencies": { + "System.Runtime": "", + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" + } + } } } From a7210c9938a22c3db3bce6d63546f9dac418b228 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 26 Mar 2014 14:19:12 -0700 Subject: [PATCH 023/597] Test: Move xunit attribute to AssemblyInfo. --- .../Properties/AssemblyInfo.cs | 3 +++ test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs index 486c5d20cd..c596cb6438 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs @@ -40,3 +40,6 @@ using System.Runtime.InteropServices; // [assembly: AssemblyVersion("0.5")] [assembly: AssemblyVersion("0.5")] [assembly: AssemblyFileVersion("0.5.40117.0")] + +// These tests can't run in parallel because they all use the same port. +[assembly: Xunit.CollectionBehaviorAttribute(Xunit.CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs index adacfdf832..eba2edfd9e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs @@ -4,9 +4,6 @@ using System.Threading.Tasks; using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Hosting.Server; -// These tests can't run in parallel because they all use the same port. -[assembly: Xunit.CollectionBehaviorAttribute(Xunit.CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] - namespace Microsoft.AspNet.Server.WebListener.Test { using AppFunc = Func; From 3ff8eba3a7b1715277e3fcb5f69c52d770724403 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 26 Mar 2014 14:28:54 -0700 Subject: [PATCH 024/597] Rename test project as FunctionalTests. --- WebListener.sln | 24 +++++++++---------- .../AuthenticationTests.cs | 11 ++------- .../HttpsTests.cs | 9 ++----- .../OpaqueUpgradeTests.cs | 9 +++---- .../Properties/AssemblyInfo.cs | 4 ++-- .../RequestBodyTests.cs | 11 ++------- .../RequestHeaderTests.cs | 11 ++------- .../RequestTests.cs | 11 ++------- .../ResponseBodyTests.cs | 11 ++------- .../ResponseHeaderTests.cs | 14 +++-------- .../ResponseSendFileTests.cs | 8 ++----- .../ResponseTests.cs | 12 ++-------- .../ServerTests.cs | 11 ++------- .../Utilities.cs | 11 ++++----- .../project.json | 0 15 files changed, 43 insertions(+), 114 deletions(-) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/AuthenticationTests.cs (91%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/HttpsTests.cs (94%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/OpaqueUpgradeTests.cs (97%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/Properties/AssemblyInfo.cs (94%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/RequestBodyTests.cs (92%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/RequestHeaderTests.cs (89%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/RequestTests.cs (93%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/ResponseBodyTests.cs (95%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/ResponseHeaderTests.cs (96%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/ResponseSendFileTests.cs (97%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/ResponseTests.cs (91%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/ServerTests.cs (95%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/Utilities.cs (88%) rename test/{Microsoft.AspNet.Server.WebListener.Test => Microsoft.AspNet.Server.WebListener.FunctionalTests}/project.json (100%) diff --git a/WebListener.sln b/WebListener.sln index 9f18ac98c5..1037bd9799 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.30110.0 +VisualStudioVersion = 12.0.30203.2 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -21,14 +21,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld.net45", "samples EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelfHostServer.net45", "samples\SelfHostServer\SelfHostServer.net45.csproj", "{96C67B2F-9913-4E8D-B2E8-969BE66B71B6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.Test.net45", "test\Microsoft.AspNet.Server.WebListener.Test\Microsoft.AspNet.Server.WebListener.Test.net45.csproj", "{485DAC59-A1F1-4D47-98BF-B448C994E05B}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld.k10", "samples\HelloWorld\HelloWorld.k10.csproj", "{A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.Windows.net45", "src\Microsoft.AspNet.Security.Windows\Microsoft.AspNet.Security.Windows.net45.csproj", "{8B4EF749-251D-4222-AD18-DE5A1E7D321A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.Windows.Test.net45", "test\Microsoft.AspNet.Security.Windows.Test\Microsoft.AspNet.Security.Windows.Test.net45.csproj", "{3EC418D5-C8FD-47AA-BFED-F524358EC3DD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests.net45", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.net45.csproj", "{E7841BDA-EEE0-42D8-8E09-48F021B1934E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -59,10 +59,6 @@ Global {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Debug|Any CPU.Build.0 = Debug|Any CPU {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Release|Any CPU.ActiveCfg = Release|Any CPU {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Release|Any CPU.Build.0 = Release|Any CPU - {485DAC59-A1F1-4D47-98BF-B448C994E05B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {485DAC59-A1F1-4D47-98BF-B448C994E05B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {485DAC59-A1F1-4D47-98BF-B448C994E05B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {485DAC59-A1F1-4D47-98BF-B448C994E05B}.Release|Any CPU.Build.0 = Release|Any CPU {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Debug|Any CPU.Build.0 = Debug|Any CPU {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -75,20 +71,24 @@ Global {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Debug|Any CPU.Build.0 = Debug|Any CPU {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Release|Any CPU.Build.0 = Release|Any CPU + {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {485DAC59-A1F1-4D47-98BF-B448C994E05B} = {E183C826-1360-4DFF-9994-F33CED5C8525} - {3EC418D5-C8FD-47AA-BFED-F524358EC3DD} = {E183C826-1360-4DFF-9994-F33CED5C8525} {8B828433-B333-4C19-96AE-00BFFF9D8841} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {BF335732-BB09-49A1-8676-F074047E7DB2} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {96C67B2F-9913-4E8D-B2E8-969BE66B71B6} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {6D9D3023-3ED7-4C95-80F0-347843ABD759} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {253B9134-B6EB-4E59-8725-D983FD941A21} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {00C6A882-1FE2-4769-901C-023D8DC175C4} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {BF335732-BB09-49A1-8676-F074047E7DB2} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {96C67B2F-9913-4E8D-B2E8-969BE66B71B6} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {8B4EF749-251D-4222-AD18-DE5A1E7D321A} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {3EC418D5-C8FD-47AA-BFED-F524358EC3DD} = {E183C826-1360-4DFF-9994-F33CED5C8525} + {E7841BDA-EEE0-42D8-8E09-48F021B1934E} = {E183C826-1360-4DFF-9994-F33CED5C8525} EndGlobalSection EndGlobal diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs similarity index 91% rename from test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 9f8887a5c8..893fc4c941 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -1,11 +1,6 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -13,10 +8,8 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - public class AuthenticationTests { private const string Address = "http://localhost:8080/"; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs similarity index 94% rename from test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index d96effc06c..73b417ff4a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -1,10 +1,5 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. -using System; using System.IO; using System.Net.Http; using System.Security.Cryptography.X509Certificates; @@ -15,7 +10,7 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { public class HttpsTests { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs similarity index 97% rename from test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index e7ddf53495..45097046fa 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -1,8 +1,5 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + /* TODO: Opaque using System; using System.Collections.Generic; @@ -15,7 +12,7 @@ using System.Threading.Tasks; using Xunit; using Xunit.Extensions; -namespace Microsoft.AspNet.Server.WebListener.Tests +namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; using OpaqueUpgrade = Action, Func, Task>>; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs similarity index 94% rename from test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs index c596cb6438..9b52afa8d6 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/Properties/AssemblyInfo.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs @@ -11,11 +11,11 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Microsoft.AspNet.Server.WebListener.Tests")] +[assembly: AssemblyTitle("Microsoft.AspNet.Server.WebListener.FunctionalTests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.AspNet.Server.WebListener.Tests")] +[assembly: AssemblyProduct("Microsoft.AspNet.Server.WebListener.FunctionalTests")] [assembly: AssemblyCopyright("Copyright © 2012")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs similarity index 92% rename from test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 59df978897..81a90c6fcd 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -1,11 +1,6 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; @@ -15,10 +10,8 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - public class RequestBodyTests { private const string Address = "http://localhost:8080/"; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs similarity index 89% rename from test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index 3ebb24eaca..b400e8b375 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -1,11 +1,6 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Net.Http; using System.Net.Sockets; using System.Text; @@ -14,10 +9,8 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - public class RequestHeaderTests { private const string Address = "http://localhost:8080/"; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs similarity index 93% rename from test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index dcfa78eab3..041665d0bb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -1,23 +1,16 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Text; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs similarity index 95% rename from test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 0372b63a39..0bb29b774f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -1,8 +1,4 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; @@ -12,14 +8,11 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - public class ResponseBodyTests { private const string Address = "http://localhost:8080/"; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs similarity index 96% rename from test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 59ce482ed5..11eff9ff14 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -1,13 +1,8 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; -using System.Collections.Generic; -using System.IO; using System.Linq; +using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; @@ -15,11 +10,8 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - using System.Net; - public class ResponseHeaderTests { private const string Address = "http://localhost:8080/"; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs similarity index 97% rename from test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 19d790fffa..4e0e4b1f27 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -1,8 +1,4 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; @@ -18,7 +14,7 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { public class ResponseSendFileTests { diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs similarity index 91% rename from test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index a9f33067aa..55d6a84562 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -1,11 +1,6 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -14,11 +9,8 @@ using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - using Microsoft.AspNet.Hosting.Server; - public class ResponseTests { private const string Address = "http://localhost:8080/"; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs similarity index 95% rename from test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index c3632fa4c3..5b8b79d68f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -1,8 +1,4 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; @@ -17,11 +13,8 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.Test +namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - using Microsoft.AspNet.Hosting.Server; - public class ServerTests { private const string Address = "http://localhost:8080/"; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs similarity index 88% rename from test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index eba2edfd9e..57dab56d0c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.Test/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -1,10 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNet.Abstractions; -using Microsoft.AspNet.Hosting.Server; +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. -namespace Microsoft.AspNet.Server.WebListener.Test +using System; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; diff --git a/test/Microsoft.AspNet.Server.WebListener.Test/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.Test/project.json rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json From 36a2524780f8c3a90eff11fec0aa4bba6d13b000 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 28 Mar 2014 00:23:16 -0700 Subject: [PATCH 025/597] Updated CLR dependencies --- samples/HelloWorld/project.json | 4 ++-- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 032365c3bb..f015cf95d6 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -12,8 +12,8 @@ "System.Globalization": "4.0.10.0", "System.IO" : "4.0.0.0", "System.Runtime" : "4.0.20.0", - "System.Threading.Tasks": "4.0.0.0", - "System.Text.Encoding": "4.0.10.0" + "System.Threading.Tasks": "4.0.10.0", + "System.Text.Encoding": "4.0.20.0" } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 38ac1dbd11..5fe79763d7 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -36,7 +36,7 @@ "System.Text.Encoding.Extensions": "4.0.10.0", "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", - "System.Threading.Tasks": "4.0.0.0", + "System.Threading.Tasks": "4.0.10.0", "System.Threading.ThreadPool": "4.0.10.0" } } From af1a97cd7c3b5d9177b9b342983b763ff53ce2b3 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 28 Mar 2014 10:36:25 -0700 Subject: [PATCH 026/597] WebListener: Normalize request read validation. 0 size is invalid. Return 0 if closed. --- .../RequestProcessing/RequestStream.cs | 49 +++------- .../RequestBodyTests.cs | 93 +++++++++++++++++++ 2 files changed, 107 insertions(+), 35 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs index 5c73f0d41c..e39f146c67 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs @@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Server.WebListener throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } - public override unsafe int Read([In, Out] byte[] buffer, int offset, int size) + private void ValidateReadBuffer(byte[] buffer, int offset, int size) { if (buffer == null) { @@ -99,15 +99,19 @@ namespace Microsoft.AspNet.Server.WebListener } if (offset < 0 || offset > buffer.Length) { - throw new ArgumentOutOfRangeException("offset"); + throw new ArgumentOutOfRangeException("offset", offset, string.Empty); } - if (size < 0 || size > buffer.Length - offset) + if (size <= 0 || size > buffer.Length - offset) { - throw new ArgumentOutOfRangeException("size"); + throw new ArgumentOutOfRangeException("size", size, string.Empty); } - if (size == 0 || _closed) + } + + public override unsafe int Read([In, Out] byte[] buffer, int offset, int size) + { + ValidateReadBuffer(buffer, offset, size); + if (_closed) { - // TODO: zero sized buffer should be invalid. return 0; } // TODO: Verbose log parameters @@ -177,19 +181,8 @@ namespace Microsoft.AspNet.Server.WebListener public unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #endif { - 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"); - } - if (size == 0 || _closed) + ValidateReadBuffer(buffer, offset, size); + if (_closed) { RequestStreamAsyncResult result = new RequestStreamAsyncResult(this, state, callback); result.Complete(0); @@ -303,26 +296,12 @@ namespace Microsoft.AspNet.Server.WebListener public override unsafe Task ReadAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken) { - 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"); - } + ValidateReadBuffer(buffer, offset, size); if (_closed) - { - throw new ObjectDisposedException(GetType().FullName); - } - if (size == 0) { return Task.FromResult(0); } + // TODO: Needs full cancellation integration cancellationToken.ThrowIfCancellationRequested(); // TODO: Verbose log parameters diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 81a90c6fcd..07ec7bf520 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -4,6 +4,8 @@ using System; using System.IO; using System.Net; using System.Net.Http; +using System.Net.Sockets; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; @@ -69,6 +71,29 @@ namespace Microsoft.AspNet.Server.WebListener } } #endif + + [Fact] + public async Task RequestBody_InvalidBuffer_ArgumentException() + { + using (Utilities.CreateHttpServer(env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + byte[] input = new byte[100]; + Assert.Throws("buffer", () => httpContext.Request.Body.Read(null, 0, 1)); + Assert.Throws("offset", () => httpContext.Request.Body.Read(input, -1, 1)); + Assert.Throws("offset", () => httpContext.Request.Body.Read(input, input.Length + 1, 1)); + Assert.Throws("size", () => httpContext.Request.Body.Read(input, 10, -1)); + Assert.Throws("size", () => httpContext.Request.Body.Read(input, 0, 0)); + Assert.Throws("size", () => httpContext.Request.Body.Read(input, 1, input.Length)); + Assert.Throws("size", () => httpContext.Request.Body.Read(input, 0, input.Length + 1)); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(Address, "Hello World"); + Assert.Equal(string.Empty, response); + } + } + [Fact] public async Task RequestBody_ReadSyncPartialBody_Success() { @@ -110,6 +135,29 @@ namespace Microsoft.AspNet.Server.WebListener } } + [Fact] + public async Task RequestBody_PostWithImidateBody_Success() + { + using (Utilities.CreateHttpServer(async env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + byte[] input = new byte[11]; + int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); + Assert.Equal(10, read); + read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); + Assert.Equal(0, read); + httpContext.Response.ContentLength = 10; + await httpContext.Response.Body.WriteAsync(input, 0, 10); + })) + { + string response = await SendSocketRequestAsync(Address); + string[] lines = response.Split('\r', '\n'); + Assert.Equal(13, lines.Length); + Assert.Equal("HTTP/1.1 200 OK", lines[0]); + Assert.Equal("0123456789", lines[12]); + } + } + private Task SendRequestAsync(string uri, string upload) { return SendRequestAsync(uri, new StringContent(upload)); @@ -125,6 +173,51 @@ namespace Microsoft.AspNet.Server.WebListener } } + private async Task SendSocketRequestAsync(string address) + { + // Connect with a socket + Uri uri = new Uri(address); + TcpClient client = new TcpClient(); + try + { + await client.ConnectAsync(uri.Host, uri.Port); + NetworkStream stream = client.GetStream(); + + // Send an HTTP GET request + byte[] requestBytes = BuildPostRequest(uri); + await stream.WriteAsync(requestBytes, 0, requestBytes.Length); + StreamReader reader = new StreamReader(stream); + return await reader.ReadToEndAsync(); + } + catch (Exception) + { + client.Close(); + throw; + } + } + + private byte[] BuildPostRequest(Uri uri) + { + StringBuilder builder = new StringBuilder(); + builder.Append("POST"); + builder.Append(" "); + builder.Append(uri.PathAndQuery); + builder.Append(" HTTP/1.1"); + builder.AppendLine(); + + builder.Append("Host: "); + builder.Append(uri.Host); + builder.Append(':'); + builder.Append(uri.Port); + builder.AppendLine(); + + builder.AppendLine("Connection: close"); + builder.AppendLine("Content-Length: 10"); + builder.AppendLine(); + builder.Append("0123456789"); + return Encoding.ASCII.GetBytes(builder.ToString()); + } + private class StaggardContent : HttpContent { public StaggardContent() From 60f09fbc939d36195f0142909d23263b726d1e64 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 31 Mar 2014 12:47:28 -0700 Subject: [PATCH 027/597] Make lower level public API. Layering. --- samples/HelloWorld/Program.cs | 104 ++++++++------ .../OwinWebListener.cs | 8 +- .../RequestProcessing/BoundaryType.cs | 8 +- .../RequestProcessing/EntitySendFormat.cs | 17 --- .../RequestProcessing/FeatureContext.cs | 14 +- .../RequestProcessing/Request.cs | 77 +++++----- .../RequestProcessing/RequestContext.cs | 47 ++----- .../RequestProcessing/Response.cs | 131 ++++++++++++------ .../RequestProcessing/ResponseStream.cs | 6 +- .../WebListenerException.cs | 19 +-- .../WebListenerWrapper.cs | 11 +- .../System/ComponentModel/Win32Exception.cs | 112 --------------- .../project.json | 3 +- 13 files changed, 236 insertions(+), 321 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs delete mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 5e176ff7ee..829908c001 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -1,55 +1,69 @@ using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; using System.Text; -using System.Threading.Tasks; using Microsoft.AspNet.Server.WebListener; -using AppFunc = System.Func, System.Threading.Tasks.Task>; - -public class Program +namespace HelloWorld { - public static void Main(string[] args) + public class Program { - using (CreateServer(new AppFunc(HelloWorldApp))) + public static void Main(string[] args) { - Console.WriteLine("Running, press enter to exit..."); - Console.ReadLine(); + using (OwinWebListener listener = new OwinWebListener()) + { + listener.UrlPrefixes.Add(UrlPrefix.Create("http://localhost:8080")); + listener.Start(); + + Console.WriteLine("Running..."); + while (true) + { + RequestContext context = listener.GetContextAsync().Result; + Console.WriteLine("Accepted"); + + // Context: + // context.User; + // context.DisconnectToken + // context.Dispose() + // context.Abort(); + + // Request + // context.Request.ProtocolVersion + // context.Request.IsLocal + // context.Request.Headers // TODO: Header helpers? + // context.Request.Method + // context.Request.Body + // Content-Length - long? + // Content-Type - string + // IsSecureConnection + // HasEntityBody + + // TODO: Request fields + // Content-Encoding - Encoding + // Host + // Client certs - GetCertAsync, CertErrors + // Cookies + // KeepAlive + // QueryString (parsed) + // RequestTraceIdentifier + // RawUrl + // URI + // IsWebSocketRequest + // LocalEndpoint vs LocalIP & LocalPort + // RemoteEndpoint vs RemoteIP & RemotePort + // AcceptTypes string[] + // ServiceName + // TransportContext + + // Response + byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); + + context.Response.ContentLength = bytes.Length; + context.Response.ContentType = "text/plain"; + + context.Response.Body.Write(bytes, 0, bytes.Length); + context.Dispose(); + } + } } } - - private static IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - - public static Task HelloWorldApp(IDictionary environment) - { - string responseText = "Hello World"; - byte[] responseBytes = Encoding.UTF8.GetBytes(responseText); - - // See http://owin.org/spec/owin-1.0.0.html for standard environment keys. - Stream responseStream = (Stream)environment["owin.ResponseBody"]; - IDictionary responseHeaders = - (IDictionary)environment["owin.ResponseHeaders"]; - - responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) }; - responseHeaders["Content-Type"] = new string[] { "text/plain" }; - - return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length); - } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index cc76380f53..bdb7a0ba83 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Server.WebListener // The native request queue private long? _requestQueueLength; - internal OwinWebListener() + public OwinWebListener() { if (!UnsafeNclNativeMethods.HttpApi.Supported) { @@ -149,7 +149,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal bool IsListening + public bool IsListening { get { @@ -332,7 +332,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal void Start() + public void Start() { CheckDisposed(); @@ -639,7 +639,7 @@ namespace Microsoft.AspNet.Server.WebListener } [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by callback")] - internal Task GetContextAsync() + public Task GetContextAsync() { AsyncAcceptContext asyncResult = null; try diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs index 6d9ca0b4e2..d6f4fd2007 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs @@ -8,11 +8,9 @@ namespace Microsoft.AspNet.Server.WebListener { internal enum BoundaryType { - ContentLength = 0, // Content-Length: XXX + None = 0, Chunked = 1, // Transfer-Encoding: chunked - Raw = 2, // the app is responsible for sending the correct headers and body encoding - Multipart = 3, - None = 4, - Invalid = 5, + ContentLength = 2, // Content-Length: XXX + Invalid = 3, } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs deleted file mode 100644 index f6861f9bd6..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs +++ /dev/null @@ -1,17 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.AspNet.Server.WebListener -{ - internal enum EntitySendFormat - { - ContentLength = 0, // Content-Length: XXX - Chunked = 1, // Transfer-Encoding: chunked - /* - Raw = 2, // the app is responsible for sending the correct headers and body encoding - */ - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs index 786256daab..81f20ef260 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs @@ -163,7 +163,19 @@ namespace Microsoft.AspNet.Server.WebListener { if (_httpProtocolVersion == null) { - _httpProtocolVersion = Request.Protocol; + if (Request.ProtocolVersion.Major == 1) + { + if (Request.ProtocolVersion.Minor == 1) + { + _httpProtocolVersion = "HTTP/1.1"; + } + else if (Request.ProtocolVersion.Minor == 0) + { + _httpProtocolVersion = "HTTP/1.0"; + } + } + + _httpProtocolVersion = "HTTP/" + Request.ProtocolVersion.ToString(2); } return _httpProtocolVersion; } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index 2136b96bae..3535dc3612 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -19,7 +19,7 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.Server.WebListener { - internal sealed class Request : IDisposable + public sealed class Request { private RequestContext _requestContext; private NativeRequestContext _nativeRequestContext; @@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Server.WebListener private IDictionary _headers; private BoundaryType _contentBoundaryType; - private long _contentLength; + private long? _contentLength; private Stream _nativeStream; private SocketAddress _localEndPoint; @@ -202,32 +202,30 @@ namespace Microsoft.AspNet.Server.WebListener } } - // TODO: Move this to the constructor, that's where it will be called. - internal long ContentLength64 + public long? ContentLength { get { if (_contentBoundaryType == BoundaryType.None) { string transferEncoding = Headers.Get(HttpKnownHeaderNames.TransferEncoding) ?? string.Empty; - if ("chunked".Equals(transferEncoding.Trim(), StringComparison.OrdinalIgnoreCase)) + if (string.Equals("chunked", transferEncoding.Trim(), StringComparison.OrdinalIgnoreCase)) { _contentBoundaryType = BoundaryType.Chunked; - _contentLength = -1; } else { - _contentLength = 0; - _contentBoundaryType = BoundaryType.ContentLength; string length = Headers.Get(HttpKnownHeaderNames.ContentLength) ?? string.Empty; - if (length != null) + long value; + if (long.TryParse(length.Trim(), NumberStyles.None, + CultureInfo.InvariantCulture.NumberFormat, out value)) { - if (!long.TryParse(length.Trim(), NumberStyles.None, - CultureInfo.InvariantCulture.NumberFormat, out _contentLength)) - { - _contentLength = 0; - _contentBoundaryType = BoundaryType.Invalid; - } + _contentBoundaryType = BoundaryType.ContentLength; + _contentLength = value; + } + else + { + _contentBoundaryType = BoundaryType.Invalid; } } } @@ -252,7 +250,6 @@ namespace Microsoft.AspNet.Server.WebListener { if (_nativeStream == null) { - // TODO: Move this to the constructor (or a lazy Env dictionary) _nativeStream = HasEntityBody ? new RequestStream(RequestContext) : Stream.Null; } return _nativeStream; @@ -281,7 +278,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal bool IsSecureConnection + public bool IsSecureConnection { get { @@ -297,7 +294,7 @@ namespace Microsoft.AspNet.Server.WebListener } } */ - internal Version ProtocolVersion + public Version ProtocolVersion { get { @@ -305,34 +302,13 @@ namespace Microsoft.AspNet.Server.WebListener } } - public string Protocol + public bool HasEntityBody { get { - if (_httpVersion.Major == 1) - { - if (_httpVersion.Minor == 1) - { - return "HTTP/1.1"; - } - else if (_httpVersion.Minor == 0) - { - return "HTTP/1.0"; - } - } - - return "HTTP/" + _httpVersion.ToString(2); - } - } - - // TODO: Move this to the constructor - internal bool HasEntityBody - { - get - { - // accessing the ContentLength property delay creates m_BoundaryType - return (ContentLength64 > 0 && _contentBoundaryType == BoundaryType.ContentLength) || - _contentBoundaryType == BoundaryType.Chunked || _contentBoundaryType == BoundaryType.Multipart; + // accessing the ContentLength property delay creates _contentBoundaryType + return (ContentLength.HasValue && ContentLength.Value > 0 && _contentBoundaryType == BoundaryType.ContentLength) + || _contentBoundaryType == BoundaryType.Chunked; } } @@ -418,6 +394,14 @@ namespace Microsoft.AspNet.Server.WebListener } } + public string ContentType + { + get + { + return Headers.Get(HttpKnownHeaderNames.ContentLength); + } + } + internal IPrincipal User { get { return _user; } @@ -443,6 +427,11 @@ namespace Microsoft.AspNet.Server.WebListener #endif } + internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod() + { + return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress); + } + #if NET45 // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to @@ -500,7 +489,7 @@ namespace Microsoft.AspNet.Server.WebListener } // should only be called from RequestContext - public void Dispose() + internal void Dispose() { // TODO: Verbose log _isDisposed = true; diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs index b326432b45..1325eaed14 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs @@ -6,9 +6,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Logging; @@ -17,14 +17,11 @@ namespace Microsoft.AspNet.Server.WebListener { using OpaqueFunc = Func, Task>; - internal sealed class RequestContext : IDisposable + public sealed class RequestContext : IDisposable { - private static readonly string[] ZeroContentLength = new[] { "0" }; - private OwinWebListener _server; private Request _request; private Response _response; - private CancellationTokenSource _cts; private NativeRequestContext _memoryBlob; private OpaqueFunc _opaqueCallback; private bool _disposed; @@ -38,11 +35,10 @@ namespace Microsoft.AspNet.Server.WebListener _memoryBlob = memoryBlob; _request = new Request(this, _memoryBlob); _response = new Response(this); - _cts = new CancellationTokenSource(); _request.ReleasePins(); } - internal Request Request + public Request Request { get { @@ -50,7 +46,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal Response Response + public Response Response { get { @@ -58,7 +54,12 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal CancellationToken DisconnectToken + public IPrincipal User + { + get { return _request.User; } + } + + public CancellationToken DisconnectToken { get { @@ -146,32 +147,20 @@ namespace Microsoft.AspNet.Server.WebListener finally { _request.Dispose(); - _cts.Dispose(); } } - internal void Abort() + public void Abort() { + // May be called from Dispose() code path, don't check _disposed. // TODO: Verbose log _disposed = true; - try - { - _cts.Cancel(); - } - catch (ObjectDisposedException) - { - } - catch (AggregateException) + if (_disconnectRegistration.HasValue) { + _disconnectRegistration.Value.Dispose(); } ForceCancelRequest(RequestQueueHandle, _request.RequestId); _request.Dispose(); - _cts.Dispose(); - } - - internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod() - { - return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(Request.RequestBuffer, Request.OriginalBlobAddress); } // This is only called while processing incoming requests. We don't have to worry about cancelling @@ -256,13 +245,5 @@ namespace Microsoft.AspNet.Server.WebListener return opaqueEnv; } - - internal void SetFatalResponse() - { - Response.StatusCode = 500; - Response.ReasonPhrase = string.Empty; - Response.Headers.Clear(); - Response.Headers.Add(HttpKnownHeaderNames.ContentLength, ZeroContentLength); - } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs index 1db2216f9c..2364e2a777 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading; @@ -15,8 +16,10 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.Server.WebListener { - internal sealed unsafe class Response : IDisposable + public sealed unsafe class Response { + private static readonly string[] ZeroContentLength = new[] { "0" }; + private ResponseState _responseState; private IDictionary _headers; private string _reasonPhrase; @@ -99,7 +102,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal ResponseStream Body + public Stream Body { get { @@ -136,14 +139,6 @@ namespace Microsoft.AspNet.Server.WebListener return true; } - internal EntitySendFormat EntitySendFormat - { - get - { - return (EntitySendFormat)_boundaryType; - } - } - public IDictionary Headers { get { return _headers; } @@ -157,7 +152,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal long ContentLength64 + internal long CalculatedLength { get { @@ -165,6 +160,73 @@ namespace Microsoft.AspNet.Server.WebListener } } + // Header accessors + public long? ContentLength + { + get + { + string contentLengthString = Headers.Get(HttpKnownHeaderNames.ContentLength); + long contentLength; + if (!string.IsNullOrWhiteSpace(contentLengthString)) + { + contentLengthString = contentLengthString.Trim(); + if (string.Equals("0", contentLengthString, StringComparison.Ordinal)) + { + return 0; + } + else if (long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out contentLength)) + { + return contentLength; + } + } + return null; + } + set + { + CheckResponseStarted(); + if (!value.HasValue) + { + Headers.Remove(HttpKnownHeaderNames.ContentLength); + } + else + { + if (value.Value < 0) + { + throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative."); + } + + if (value.Value == 0) + { + Headers[HttpKnownHeaderNames.ContentLength] = ZeroContentLength; + } + else + { + Headers[HttpKnownHeaderNames.ContentLength] = new[] { value.Value.ToString(CultureInfo.InvariantCulture) }; + } + } + } + } + + public string ContentType + { + get + { + return Headers.Get(HttpKnownHeaderNames.ContentLength); + } + set + { + CheckResponseStarted(); + if (string.IsNullOrEmpty(value)) + { + Headers.Remove(HttpKnownHeaderNames.ContentType); + } + else + { + Headers[HttpKnownHeaderNames.ContentType] = new[] { value }; + } + } + } + private Version GetProtocolVersion() { /* @@ -203,24 +265,17 @@ namespace Microsoft.AspNet.Server.WebListener return Request.ProtocolVersion; } - public void Dispose() + // should only be called from RequestContext + internal void Dispose() { - Dispose(true); - } - - private void Dispose(bool disposing) - { - if (disposing) + if (_responseState >= ResponseState.Closed) { - if (_responseState >= ResponseState.Closed) - { - return; - } - // TODO: Verbose log - EnsureResponseStream(); - _nativeStream.Dispose(); - _responseState = ResponseState.Closed; + return; } + // TODO: Verbose log + EnsureResponseStream(); + _nativeStream.Dispose(); + _responseState = ResponseState.Closed; } // old API, now private, and helper methods @@ -434,7 +489,7 @@ namespace Microsoft.AspNet.Server.WebListener } // Content-Length takes priority - string contentLengthString = Headers.Get(HttpKnownHeaderNames.ContentLength); + long? contentLength = ContentLength; string transferEncodingString = Headers.Get(HttpKnownHeaderNames.TransferEncoding); if (responseVersion == Constants.V1_0 && !string.IsNullOrEmpty(transferEncodingString) @@ -445,27 +500,14 @@ namespace Microsoft.AspNet.Server.WebListener transferEncodingString = null; } - if (!string.IsNullOrWhiteSpace(contentLengthString)) + if (contentLength.HasValue) { - contentLengthString = contentLengthString.Trim(); - if (string.Equals("0", contentLengthString, StringComparison.Ordinal)) + _contentLength = contentLength.Value; + _boundaryType = BoundaryType.ContentLength; + if (_contentLength == 0) { - _boundaryType = BoundaryType.ContentLength; - _contentLength = 0; flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; } - else if (long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out _contentLength)) - { - _boundaryType = BoundaryType.ContentLength; - if (_contentLength == 0) - { - flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; - } - } - else - { - _boundaryType = BoundaryType.Invalid; - } } else if (!string.IsNullOrWhiteSpace(transferEncodingString) && string.Equals("chunked", transferEncodingString.Trim(), StringComparison.OrdinalIgnoreCase)) @@ -509,7 +551,6 @@ namespace Microsoft.AspNet.Server.WebListener } // Also, Keep-Alive vs Connection Close - if (!keepAlive) { if (!closeSet) diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs index 45c3d698ff..8d49f85ca3 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs @@ -195,14 +195,14 @@ namespace Microsoft.AspNet.Server.WebListener } if (_leftToWrite == long.MinValue) { - UnsafeNclNativeMethods.HttpApi.HTTP_VERB method = _requestContext.GetKnownMethod(); + UnsafeNclNativeMethods.HttpApi.HTTP_VERB method = _requestContext.Request.GetKnownMethod(); if (method == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD) { _leftToWrite = 0; } - else if (_requestContext.Response.EntitySendFormat == EntitySendFormat.ContentLength) + else if (_requestContext.Response.BoundaryType == BoundaryType.ContentLength) { - _leftToWrite = _requestContext.Response.ContentLength64; + _leftToWrite = _requestContext.Response.CalculatedLength; } else { diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs index 19a7b78a6e..63c5f1713e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs @@ -1,19 +1,18 @@ //------------------------------------------------------------------------------ -// +// // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ using System; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace Microsoft.AspNet.Server.WebListener { -#if NET45 - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] -#endif - internal class WebListenerException : Win32Exception + [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] + public class WebListenerException : Win32Exception { internal WebListenerException() : base(Marshal.GetLastWin32Error()) @@ -29,12 +28,14 @@ namespace Microsoft.AspNet.Server.WebListener : base(errorCode, message) { } - +#if NET45 + // the base class returns the HResult with this property + // we need the Win32 Error Code, hence the override. public override int ErrorCode +#else + public int ErrorCode +#endif { - // the base class returns the HResult with this property - // we need the Win32 Error Code, hence the override. - get { return NativeErrorCode; diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs index 1986d8d3de..e274221a13 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs @@ -139,7 +139,7 @@ namespace Microsoft.AspNet.Server.WebListener else { // We haven't sent a response yet, try to send a 500 Internal Server Error - requestContext.SetFatalResponse(); + SetFatalResponse(requestContext); } } requestContext.Dispose(); @@ -148,10 +148,17 @@ namespace Microsoft.AspNet.Server.WebListener { LogHelper.LogException(_logger, "ProcessRequestAsync", ex); requestContext.Abort(); - requestContext.Dispose(); } } + private static void SetFatalResponse(RequestContext context) + { + context.Response.StatusCode = 500; + context.Response.ReasonPhrase = string.Empty; + context.Response.Headers.Clear(); + context.Response.ContentLength = 0; + } + public void Dispose() { _listener.Dispose(); diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs deleted file mode 100644 index 108303ee2c..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs +++ /dev/null @@ -1,112 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -#if !NET45 - -using System.Runtime.InteropServices; -using System.Text; - -namespace System.ComponentModel -{ - internal class Win32Exception : ExternalException - { - /// - /// Represents the Win32 error code associated with this exception. This - /// field is read-only. - /// - private readonly int nativeErrorCode; - - /// - /// Initializes a new instance of the class with the last Win32 error - /// that occured. - /// - public Win32Exception() - : this(Marshal.GetLastWin32Error()) - { - } - /// - /// Initializes a new instance of the class with the specified error. - /// - public Win32Exception(int error) - : this(error, GetErrorMessage(error)) - { - } - /// - /// Initializes a new instance of the class with the specified error and the - /// specified detailed description. - /// - public Win32Exception(int error, string message) - : base(message) - { - nativeErrorCode = error; - } - - /// - /// Initializes a new instance of the Exception class with a specified error message. - /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. - /// - public Win32Exception(string message) - : this(Marshal.GetLastWin32Error(), message) - { - } - - /// - /// Initializes a new instance of the Exception class with a specified error message and a - /// reference to the inner exception that is the cause of this exception. - /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. - /// - public Win32Exception(string message, Exception innerException) - : base(message, innerException) - { - nativeErrorCode = Marshal.GetLastWin32Error(); - } - - - /// - /// Represents the Win32 error code associated with this exception. This - /// field is read-only. - /// - public int NativeErrorCode - { - get - { - return nativeErrorCode; - } - } - - private static string GetErrorMessage(int error) - { - //get the system error message... - string errorMsg = ""; - StringBuilder sb = new StringBuilder(256); - int result = SafeNativeMethods.FormatMessage( - SafeNativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS | - SafeNativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | - SafeNativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY, - IntPtr.Zero, (uint)error, 0, sb, sb.Capacity + 1, - null); - if (result != 0) - { - int i = sb.Length; - while (i > 0) - { - char ch = sb[i - 1]; - if (ch > 32 && ch != '.') break; - i--; - } - errorMsg = sb.ToString(0, i); - } - else - { - errorMsg = "Unknown error (0x" + Convert.ToString(error, 16) + ")"; - } - - return errorMsg; - } - } -} - -#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 5fe79763d7..82efe0ab48 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -37,7 +37,8 @@ "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", "System.Threading.Tasks": "4.0.10.0", - "System.Threading.ThreadPool": "4.0.10.0" + "System.Threading.ThreadPool": "4.0.10.0", + "Microsoft.Win32.Primitives": "4.0.0.0" } } } From cb982f19bb6822b0cf394b84fe76517823f0dc8f Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 31 Mar 2014 13:05:03 -0700 Subject: [PATCH 028/597] Update samples. --- WebListener.sln | 7 ++ samples/SelfHostServer/Program.cs | 138 ---------------------------- samples/SelfHostServer/Startup.cs | 20 ++++ samples/SelfHostServer/project.json | 34 +++++-- 4 files changed, 51 insertions(+), 148 deletions(-) delete mode 100644 samples/SelfHostServer/Program.cs create mode 100644 samples/SelfHostServer/Startup.cs diff --git a/WebListener.sln b/WebListener.sln index 1037bd9799..e8e84a23e0 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.W EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests.net45", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.net45.csproj", "{E7841BDA-EEE0-42D8-8E09-48F021B1934E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelfHostServer.k10", "samples\SelfHostServer\SelfHostServer.k10.csproj", "{990662B2-A857-4DD6-85F3-F8517ACAAB13}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -75,6 +77,10 @@ Global {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Release|Any CPU.Build.0 = Release|Any CPU + {990662B2-A857-4DD6-85F3-F8517ACAAB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {990662B2-A857-4DD6-85F3-F8517ACAAB13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {990662B2-A857-4DD6-85F3-F8517ACAAB13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {990662B2-A857-4DD6-85F3-F8517ACAAB13}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -90,5 +96,6 @@ Global {8B4EF749-251D-4222-AD18-DE5A1E7D321A} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {3EC418D5-C8FD-47AA-BFED-F524358EC3DD} = {E183C826-1360-4DFF-9994-F33CED5C8525} {E7841BDA-EEE0-42D8-8E09-48F021B1934E} = {E183C826-1360-4DFF-9994-F33CED5C8525} + {990662B2-A857-4DD6-85F3-F8517ACAAB13} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} EndGlobalSection EndGlobal diff --git a/samples/SelfHostServer/Program.cs b/samples/SelfHostServer/Program.cs deleted file mode 100644 index f01efdd682..0000000000 --- a/samples/SelfHostServer/Program.cs +++ /dev/null @@ -1,138 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Owin; -using Microsoft.AspNet.Server.WebListener; -using Microsoft.Owin.Hosting; -using Owin; - -namespace SelfHostServer -{ - // http://owin.org/extensions/owin-WebSocket-Extension-v0.4.0.htm - using WebSocketAccept = Action, // options - Func, Task>>; // callback - using WebSocketCloseAsync = - Func; - using WebSocketReceiveAsync = - Func /* data */, - CancellationToken /* cancel */, - Task>>; - using WebSocketReceiveResult = Tuple; // count - using WebSocketSendAsync = - Func /* data */, - int /* messageType */, - bool /* endOfMessage */, - CancellationToken /* cancel */, - Task>; - - public class Program - { - private static byte[] Data = new byte[1024]; - - public static void Main(string[] args) - { - using (WebApp.Start(new StartOptions( - // "http://localhost:5000/" - "https://localhost:9090/" - ) - { - ServerFactory = "Microsoft.AspNet.Server.WebListener" - })) - { - Console.WriteLine("Running, press any key to exit"); - // System.Diagnostics.Process.Start("http://localhost:5000/"); - Console.ReadKey(); - } - } - - public void Configuration(IAppBuilder app) - { - OwinWebListener listener = (OwinWebListener)app.Properties["Microsoft.AspNet.Server.WebListener.OwinWebListener"]; - listener.AuthenticationManager.AuthenticationTypes = - AuthenticationType.Basic | - AuthenticationType.Digest | - AuthenticationType.Negotiate | - AuthenticationType.Ntlm | - AuthenticationType.Kerberos; - - app.Use((context, next) => - { - Console.WriteLine("Request: " + context.Request.Uri); - return next(); - }); - app.Use((context, next) => - { - if (context.Request.User == null) - { - context.Response.StatusCode = 401; - return Task.FromResult(0); - } - else - { - Console.WriteLine(context.Request.User.Identity.AuthenticationType); - } - return next(); - }); - app.UseWebSockets(); - app.Use(UpgradeToWebSockets); - app.Run(Invoke); - } - - public Task Invoke(IOwinContext context) - { - context.Response.ContentLength = Data.Length; - return context.Response.WriteAsync(Data); - } - - // Run once per request - private Task UpgradeToWebSockets(IOwinContext context, Func next) - { - WebSocketAccept accept = context.Get("websocket.Accept"); - if (accept == null) - { - // Not a websocket request - return next(); - } - - accept(null, WebSocketEcho); - - return Task.FromResult(null); - } - - private async Task WebSocketEcho(IDictionary websocketContext) - { - var sendAsync = (WebSocketSendAsync)websocketContext["websocket.SendAsync"]; - var receiveAsync = (WebSocketReceiveAsync)websocketContext["websocket.ReceiveAsync"]; - var closeAsync = (WebSocketCloseAsync)websocketContext["websocket.CloseAsync"]; - var callCancelled = (CancellationToken)websocketContext["websocket.CallCancelled"]; - - byte[] buffer = new byte[1024]; - WebSocketReceiveResult received = await receiveAsync(new ArraySegment(buffer), callCancelled); - - object status; - while (!websocketContext.TryGetValue("websocket.ClientCloseStatus", out status) || (int)status == 0) - { - // Echo anything we receive - await sendAsync(new ArraySegment(buffer, 0, received.Item3), received.Item1, received.Item2, callCancelled); - - received = await receiveAsync(new ArraySegment(buffer), callCancelled); - } - - await closeAsync((int)websocketContext["websocket.ClientCloseStatus"], (string)websocketContext["websocket.ClientCloseDescription"], callCancelled); - } - } -} diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs new file mode 100644 index 0000000000..163ce335a6 --- /dev/null +++ b/samples/SelfHostServer/Startup.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.Server.WebListener; + +namespace SelfHostServer +{ + public class Startup + { + public void Configuration(IBuilder app) + { + var info = (ServerInformation)app.Server; + info.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationType.None; + + app.Run(async context => + { + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Hello world"); + }); + } + } +} diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index ed203d2aeb..4caf1e1901 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,19 +1,33 @@ { "version" : "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Server.WebListener" : "", - "Microsoft.AspNet.WebSockets" : "" + "Microsoft.AspNet.Abstractions": "0.1-alpha-*", + "Microsoft.AspNet.Hosting": "0.1-alpha-*", + "Microsoft.AspNet.Server.WebListener": "" }, + "commands": { "web": "Microsoft.AspNet.Hosting server.name=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001" }, "configurations": { "net45": { + }, + "k10": { "dependencies": { - "Owin": "1.0", - "Microsoft.Owin": "2.1.0", - "Microsoft.Owin.Diagnostics": "2.1.0", - "Microsoft.Owin.Hosting": "2.1.0", - "Microsoft.Owin.Host.HttpListener": "2.1.0", - "Microsoft.AspNet.AppBuilderSupport": "0.1-alpha-*" - } + "System.Console": "4.0.0.0", + "System.Collections": "4.0.0.0", + "System.Diagnostics.Debug": "4.0.10.0", + "System.Diagnostics.Tools": "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO": "4.0.0.0", + "System.IO.FileSystem": "4.0.0.0", + "System.IO.FileSystem.Primitives": "4.0.0.0", + "System.Linq": "4.0.0.0", + "System.Reflection": "4.0.10.0", + "System.Resources.ResourceManager": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "System.Runtime.Extensions": "4.0.10.0", + "System.Runtime.InteropServices": "4.0.10.0", + "System.Text.Encoding": "4.0.10.0", + "System.Threading.Tasks": "4.0.10.0" + } } } -} +} \ No newline at end of file From ef5b9feb393e5486ef88259747251036c40cc4be Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 10 Apr 2014 15:04:53 -0700 Subject: [PATCH 029/597] Update sample dependencies. --- samples/HelloWorld/project.json | 3 +-- samples/SelfHostServer/project.json | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index f015cf95d6..123a203698 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -12,8 +12,7 @@ "System.Globalization": "4.0.10.0", "System.IO" : "4.0.0.0", "System.Runtime" : "4.0.20.0", - "System.Threading.Tasks": "4.0.10.0", - "System.Text.Encoding": "4.0.20.0" + "System.Threading.Tasks": "4.0.10.0" } } } diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 4caf1e1901..cb620bf621 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -24,8 +24,7 @@ "System.Resources.ResourceManager": "4.0.0.0", "System.Runtime": "4.0.20.0", "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.InteropServices": "4.0.10.0", - "System.Text.Encoding": "4.0.10.0", + "System.Runtime.InteropServices": "4.0.20.0", "System.Threading.Tasks": "4.0.10.0" } } From f8b1679240e993892dadd6daad7cdf8fdb852099 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 16 Apr 2014 14:16:46 -0700 Subject: [PATCH 030/597] Update to new project tooling. --- WebListener.sln | 148 ++++++++++-------- samples/HelloWorld/HelloWorld.kproj | 29 ++++ samples/SelfHostServer/SelfHostServer.kproj | 29 ++++ .../Microsoft.AspNet.Security.Windows.kproj | 74 +++++++++ .../Microsoft.AspNet.Server.WebListener.kproj | 95 +++++++++++ .../Microsoft.AspNet.WebSockets.kproj | 59 +++++++ ...t.Server.WebListener.FunctionalTests.kproj | 39 +++++ 7 files changed, 408 insertions(+), 65 deletions(-) create mode 100644 samples/HelloWorld/HelloWorld.kproj create mode 100644 samples/SelfHostServer/SelfHostServer.kproj create mode 100644 src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj create mode 100644 src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj create mode 100644 src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj create mode 100644 test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj diff --git a/WebListener.sln b/WebListener.sln index e8e84a23e0..fc4110ba94 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,101 +1,119 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.30203.2 +VisualStudioVersion = 12.0.30401.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.k10", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.k10.csproj", "{6D9D3023-3ED7-4C95-80F0-347843ABD759}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.net45", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.net45.csproj", "{253B9134-B6EB-4E59-8725-D983FD941A21}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebSockets.net45", "src\Microsoft.AspNet.WebSockets\Microsoft.AspNet.WebSockets.net45.csproj", "{00C6A882-1FE2-4769-901C-023D8DC175C4}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{99D5E5F3-88F5-4CCF-8D8C-717C8925DF09}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E183C826-1360-4DFF-9994-F33CED5C8525}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A1E31E3-2794-4CA3-B8E2-253E96BDE514}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld.net45", "samples\HelloWorld\HelloWorld.net45.csproj", "{BF335732-BB09-49A1-8676-F074047E7DB2}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.kproj", "{3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelfHostServer.net45", "samples\SelfHostServer\SelfHostServer.net45.csproj", "{96C67B2F-9913-4E8D-B2E8-969BE66B71B6}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\HelloWorld\HelloWorld.kproj", "{6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld.k10", "samples\HelloWorld\HelloWorld.k10.csproj", "{A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.kproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.Windows.net45", "src\Microsoft.AspNet.Security.Windows\Microsoft.AspNet.Security.Windows.net45.csproj", "{8B4EF749-251D-4222-AD18-DE5A1E7D321A}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Security.Windows", "src\Microsoft.AspNet.Security.Windows\Microsoft.AspNet.Security.Windows.kproj", "{EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.Windows.Test.net45", "test\Microsoft.AspNet.Security.Windows.Test\Microsoft.AspNet.Security.Windows.Test.net45.csproj", "{3EC418D5-C8FD-47AA-BFED-F524358EC3DD}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.WebSockets", "src\Microsoft.AspNet.WebSockets\Microsoft.AspNet.WebSockets.kproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests.net45", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.net45.csproj", "{E7841BDA-EEE0-42D8-8E09-48F021B1934E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelfHostServer.k10", "samples\SelfHostServer\SelfHostServer.k10.csproj", "{990662B2-A857-4DD6-85F3-F8517ACAAB13}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj", "{4492FF4C-9032-411D-853F-46B01755E504}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {8B828433-B333-4C19-96AE-00BFFF9D8841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8B828433-B333-4C19-96AE-00BFFF9D8841}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Debug|x86.ActiveCfg = Debug|Any CPU {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Any CPU.Build.0 = Release|Any CPU - {6D9D3023-3ED7-4C95-80F0-347843ABD759}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6D9D3023-3ED7-4C95-80F0-347843ABD759}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6D9D3023-3ED7-4C95-80F0-347843ABD759}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6D9D3023-3ED7-4C95-80F0-347843ABD759}.Release|Any CPU.Build.0 = Release|Any CPU - {253B9134-B6EB-4E59-8725-D983FD941A21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {253B9134-B6EB-4E59-8725-D983FD941A21}.Debug|Any CPU.Build.0 = Debug|Any CPU - {253B9134-B6EB-4E59-8725-D983FD941A21}.Release|Any CPU.ActiveCfg = Release|Any CPU - {253B9134-B6EB-4E59-8725-D983FD941A21}.Release|Any CPU.Build.0 = Release|Any CPU - {00C6A882-1FE2-4769-901C-023D8DC175C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {00C6A882-1FE2-4769-901C-023D8DC175C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {00C6A882-1FE2-4769-901C-023D8DC175C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {00C6A882-1FE2-4769-901C-023D8DC175C4}.Release|Any CPU.Build.0 = Release|Any CPU - {BF335732-BB09-49A1-8676-F074047E7DB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BF335732-BB09-49A1-8676-F074047E7DB2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BF335732-BB09-49A1-8676-F074047E7DB2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BF335732-BB09-49A1-8676-F074047E7DB2}.Release|Any CPU.Build.0 = Release|Any CPU - {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {96C67B2F-9913-4E8D-B2E8-969BE66B71B6}.Release|Any CPU.Build.0 = Release|Any CPU - {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B}.Release|Any CPU.Build.0 = Release|Any CPU - {8B4EF749-251D-4222-AD18-DE5A1E7D321A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8B4EF749-251D-4222-AD18-DE5A1E7D321A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8B4EF749-251D-4222-AD18-DE5A1E7D321A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8B4EF749-251D-4222-AD18-DE5A1E7D321A}.Release|Any CPU.Build.0 = Release|Any CPU - {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3EC418D5-C8FD-47AA-BFED-F524358EC3DD}.Release|Any CPU.Build.0 = Release|Any CPU - {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E7841BDA-EEE0-42D8-8E09-48F021B1934E}.Release|Any CPU.Build.0 = Release|Any CPU - {990662B2-A857-4DD6-85F3-F8517ACAAB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {990662B2-A857-4DD6-85F3-F8517ACAAB13}.Debug|Any CPU.Build.0 = Debug|Any CPU - {990662B2-A857-4DD6-85F3-F8517ACAAB13}.Release|Any CPU.ActiveCfg = Release|Any CPU - {990662B2-A857-4DD6-85F3-F8517ACAAB13}.Release|Any CPU.Build.0 = Release|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|x86.ActiveCfg = Release|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Any CPU.ActiveCfg = Debug|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|x86.ActiveCfg = Debug|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|x86.Build.0 = Debug|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Any CPU.ActiveCfg = Release|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Mixed Platforms.Build.0 = Release|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|x86.ActiveCfg = Release|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|x86.Build.0 = Release|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Any CPU.ActiveCfg = Debug|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|x86.ActiveCfg = Debug|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|x86.Build.0 = Debug|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Any CPU.ActiveCfg = Release|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Mixed Platforms.Build.0 = Release|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|x86.ActiveCfg = Release|x86 + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|x86.Build.0 = Release|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Any CPU.ActiveCfg = Debug|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|x86.ActiveCfg = Debug|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|x86.Build.0 = Debug|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Any CPU.ActiveCfg = Release|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.Build.0 = Release|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|x86.ActiveCfg = Release|x86 + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|x86.Build.0 = Release|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Any CPU.ActiveCfg = Debug|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|x86.ActiveCfg = Debug|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|x86.Build.0 = Debug|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Any CPU.ActiveCfg = Release|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Mixed Platforms.Build.0 = Release|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|x86.ActiveCfg = Release|x86 + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|x86.Build.0 = Release|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Any CPU.ActiveCfg = Debug|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|x86.ActiveCfg = Debug|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|x86.Build.0 = Debug|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Any CPU.ActiveCfg = Release|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Mixed Platforms.Build.0 = Release|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|x86.ActiveCfg = Release|x86 + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|x86.Build.0 = Release|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Any CPU.ActiveCfg = Debug|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|x86.ActiveCfg = Debug|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|x86.Build.0 = Debug|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Release|Any CPU.ActiveCfg = Release|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Release|Mixed Platforms.Build.0 = Release|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Release|x86.ActiveCfg = Release|x86 + {4492FF4C-9032-411D-853F-46B01755E504}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {8B828433-B333-4C19-96AE-00BFFF9D8841} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {6D9D3023-3ED7-4C95-80F0-347843ABD759} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} - {253B9134-B6EB-4E59-8725-D983FD941A21} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} - {00C6A882-1FE2-4769-901C-023D8DC175C4} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} - {BF335732-BB09-49A1-8676-F074047E7DB2} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {96C67B2F-9913-4E8D-B2E8-969BE66B71B6} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {A1F2CA12-3F08-4DE2-B3D9-52DBE267936B} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {8B4EF749-251D-4222-AD18-DE5A1E7D321A} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} - {3EC418D5-C8FD-47AA-BFED-F524358EC3DD} = {E183C826-1360-4DFF-9994-F33CED5C8525} - {E7841BDA-EEE0-42D8-8E09-48F021B1934E} = {E183C826-1360-4DFF-9994-F33CED5C8525} - {990662B2-A857-4DD6-85F3-F8517ACAAB13} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {1236F93A-AC5C-4A77-9477-C88F040151CA} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {4492FF4C-9032-411D-853F-46B01755E504} = {E183C826-1360-4DFF-9994-F33CED5C8525} EndGlobalSection EndGlobal diff --git a/samples/HelloWorld/HelloWorld.kproj b/samples/HelloWorld/HelloWorld.kproj new file mode 100644 index 0000000000..41a114cdcb --- /dev/null +++ b/samples/HelloWorld/HelloWorld.kproj @@ -0,0 +1,29 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 6daf3e6b-8e1b-4e6e-b9fe-7b1e5fdb7db4 + Library + + + + + + + 2.0 + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj new file mode 100644 index 0000000000..199bbb5a01 --- /dev/null +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -0,0 +1,29 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 1236f93a-ac5c-4a77-9477-c88f040151ca + Library + + + + + + + 2.0 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj new file mode 100644 index 0000000000..99d381529a --- /dev/null +++ b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj @@ -0,0 +1,74 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + efc7538f-7aeb-4a3e-a1e6-6bdccbd272bf + Library + net45 + + + + + + + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj new file mode 100644 index 0000000000..0547c1e84c --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -0,0 +1,95 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 + Library + net45 + + + + + + + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj b/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj new file mode 100644 index 0000000000..94229fc81d --- /dev/null +++ b/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj @@ -0,0 +1,59 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + e788aeae-2cb4-4bfa-8746-d0bb7e93a1bb + Library + net45 + + + + + + + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj new file mode 100644 index 0000000000..7e4afa0aed --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj @@ -0,0 +1,39 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 4492ff4c-9032-411d-853f-46b01755e504 + Library + net45 + + + + + + + 2.0 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 93aa23b6ab5ec300eb5934511177647ac9d85ea4 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sat, 19 Apr 2014 16:40:58 -0700 Subject: [PATCH 031/597] Removed ifdefs around RemoteIP and ClientCerts. --- samples/HelloWorld/HelloWorld.kproj | 3 -- .../NativeInterop/SocketAddress.cs | 4 +-- .../RequestProcessing/ClientCertLoader.cs | 4 --- .../RequestProcessing/FeatureContext.cs | 35 ++++++------------- .../RequestProcessing/Request.cs | 14 ++------ 5 files changed, 15 insertions(+), 45 deletions(-) diff --git a/samples/HelloWorld/HelloWorld.kproj b/samples/HelloWorld/HelloWorld.kproj index 41a114cdcb..878b876200 100644 --- a/samples/HelloWorld/HelloWorld.kproj +++ b/samples/HelloWorld/HelloWorld.kproj @@ -19,9 +19,6 @@ - - - diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs index 26d92e61e0..78b52c13c7 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs +++ b/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs @@ -170,7 +170,7 @@ namespace Microsoft.AspNet.Server.WebListener } return _hash; } -#if NET45 + internal IPAddress GetIPAddress() { if (Family == AddressFamily.InterNetworkV6) @@ -200,7 +200,7 @@ namespace Microsoft.AspNet.Server.WebListener Contract.Assert(Size >= IPv4AddressSize); return new IPAddress(new byte[] { _buffer[4], _buffer[5], _buffer[6], _buffer[7] }); } -#endif + public override string ToString() { StringBuilder bytes = new StringBuilder(); diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs index 3cd17db788..d5efd0b12e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs @@ -4,8 +4,6 @@ // // ----------------------------------------------------------------------- -#if NET45 - using System; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; @@ -343,5 +341,3 @@ namespace Microsoft.AspNet.Server.WebListener } } } - -#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs index 81f20ef260..b52beb029f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs @@ -2,9 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Net; -#if NET45 using System.Security.Cryptography.X509Certificates; -#endif using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; @@ -12,10 +10,7 @@ using Microsoft.AspNet.HttpFeature; namespace Microsoft.AspNet.Server.WebListener { - internal class FeatureContext : IHttpRequestInformation, IHttpConnection, IHttpResponseInformation, IHttpSendFile -#if NET45 - , IHttpTransportLayerSecurity -#endif + internal class FeatureContext : IHttpRequestInformation, IHttpConnection, IHttpResponseInformation, IHttpSendFile, IHttpTransportLayerSecurity { private RequestContext _requestContext; private FeatureCollection _features; @@ -28,16 +23,12 @@ namespace Microsoft.AspNet.Server.WebListener private string _query; private string _pathBase; private string _path; -#if NET45 private IPAddress _remoteIpAddress; private IPAddress _localIpAddress; -#endif private int? _remotePort; private int? _localPort; private bool? _isLocal; -#if NET45 private X509Certificate _clientCert; -#endif private Stream _responseStream; private IDictionary _responseHeaders; @@ -69,10 +60,8 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpConnection), this); if (Request.IsSecureConnection) { -#if NET45 // TODO: Should this feature be conditional? Should we add this for HTTP requests? _features.Add(typeof(IHttpTransportLayerSecurity), this); -#endif } _features.Add(typeof(IHttpResponseInformation), this); _features.Add(typeof(IHttpSendFile), this); @@ -90,7 +79,7 @@ namespace Microsoft.AspNet.Server.WebListener */ } -#region IHttpRequestInformation + #region IHttpRequestInformation Stream IHttpRequestInformation.Body { @@ -207,8 +196,8 @@ namespace Microsoft.AspNet.Server.WebListener } set { _scheme = value; } } -#endregion -#region IHttpConnection + #endregion + #region IHttpConnection bool IHttpConnection.IsLocal { get @@ -221,7 +210,7 @@ namespace Microsoft.AspNet.Server.WebListener } set { _isLocal = value; } } -#if NET45 + IPAddress IHttpConnection.LocalIpAddress { get @@ -247,7 +236,7 @@ namespace Microsoft.AspNet.Server.WebListener } set { _remoteIpAddress = value; } } -#endif + int IHttpConnection.LocalPort { get @@ -273,9 +262,8 @@ namespace Microsoft.AspNet.Server.WebListener } set { _remotePort = value; } } -#endregion -#region IHttpTransportLayerSecurity -#if NET45 + #endregion + #region IHttpTransportLayerSecurity X509Certificate IHttpTransportLayerSecurity.ClientCertificate { get @@ -296,9 +284,8 @@ namespace Microsoft.AspNet.Server.WebListener _clientCert = await Request.GetClientCertificateAsync(); } } -#endif -#endregion -#region IHttpResponseInformation + #endregion + #region IHttpResponseInformation Stream IHttpResponseInformation.Body { get @@ -341,7 +328,7 @@ namespace Microsoft.AspNet.Server.WebListener get { return Response.StatusCode; } set { Response.StatusCode = value; } } -#endregion + #endregion Task IHttpSendFile.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) { return Response.SendFileAsync(path, offset, length, cancellation); diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index 3535dc3612..5b7875cd08 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -10,9 +10,7 @@ using System.Globalization; using System.IO; using System.Net; using System.Runtime.InteropServices; -#if NET45 using System.Security.Cryptography.X509Certificates; -#endif using System.Security.Principal; using System.Threading; using System.Threading.Tasks; @@ -41,9 +39,7 @@ namespace Microsoft.AspNet.Server.WebListener private string _pathBase; private string _path; -#if NET45 private X509Certificate _clientCert; -#endif private IDictionary _headers; private BoundaryType _contentBoundaryType; @@ -270,11 +266,7 @@ namespace Microsoft.AspNet.Server.WebListener { get { -#if NET45 return LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress()); -#else - throw new NotImplementedException(); -#endif } } @@ -337,7 +329,7 @@ namespace Microsoft.AspNet.Server.WebListener return _localEndPoint; } } -#if NET45 + public IPAddress RemoteIpAddress { get { return RemoteEndPoint.GetIPAddress(); } @@ -347,7 +339,7 @@ namespace Microsoft.AspNet.Server.WebListener { get { return LocalEndPoint.GetIPAddress(); } } -#endif + public int RemotePort { get { return RemoteEndPoint.GetPort(); } @@ -432,7 +424,6 @@ namespace Microsoft.AspNet.Server.WebListener return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress); } -#if NET45 // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to // enable this, but it's unclear what Http.Sys would do. @@ -470,7 +461,6 @@ namespace Microsoft.AspNet.Server.WebListener } return _clientCert; } -#endif // Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be // disposed. From bfab162b4b02181bd43785edbec4d4db281cec81 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 16 Apr 2014 15:53:51 -0700 Subject: [PATCH 032/597] Seperate the server layers into two projects. --- WebListener.sln | 15 ++- samples/HelloWorld/Program.cs | 4 +- samples/HelloWorld/project.json | 2 +- samples/SelfHostServer/Startup.cs | 1 + samples/SelfHostServer/project.json | 1 + .../Microsoft.AspNet.Security.Windows.kproj | 1 - .../Properties/AssemblyInfo.cs | 42 --------- .../{fx => }/AssemblyNeutralAttribute.cs | 0 .../{RequestProcessing => }/FeatureContext.cs | 1 + .../{WebListenerWrapper.cs => MessagePump.cs} | 13 +-- .../Microsoft.AspNet.Server.WebListener.kproj | 81 ++-------------- .../ServerFactory.cs | 11 ++- .../ServerInformation.cs | 18 ++-- .../fx/IServerFactory.cs | 16 ---- .../project.json | 3 +- .../AsyncAcceptContext.cs | 12 +-- .../AuthenticationManager.cs | 8 +- .../AuthenticationTypes.cs | 2 +- .../Constants.cs | 2 +- .../CustomDictionary.xml | 0 .../DictionaryExtensions.cs | 0 .../GlobalSuppressions.cs | Bin src/Microsoft.Net.Server/Helpers.cs | 29 ++++++ src/Microsoft.Net.Server/LogHelper.cs | 74 +++++++++++++++ .../Microsoft.Net.Server.kproj | 89 ++++++++++++++++++ .../NativeInterop/AddressFamily.cs | 2 +- .../NativeInterop/ComNetOS.cs | 2 +- .../NativeInterop/ContextAttribute.cs | 2 +- .../NativeInterop/HttpRequestQueueV2Handle.cs | 2 +- .../NativeInterop/HttpServerSessionHandle.cs | 2 +- .../NativeInterop/HttpSysRequestHeader.cs | 2 +- .../NativeInterop/HttpSysResponseHeader.cs | 2 +- .../NativeInterop/HttpSysSettings.cs | 2 +- .../NativeInterop/IntPtrHelper.cs | 2 +- .../NativeInterop/NclUtilities.cs | 2 +- .../NativeInterop/SSPIHandle.cs | 2 +- .../NativeInterop/SafeLoadLibrary.cs | 2 +- .../NativeInterop/SafeLocalFree.cs | 2 +- .../SafeLocalFreeChannelBinding.cs | 2 +- .../NativeInterop/SafeLocalMemHandle.cs | 2 +- .../NativeInterop/SafeNativeOverlapped.cs | 2 +- .../NativeInterop/SchProtocols.cs | 2 +- .../NativeInterop/SecurityStatus.cs | 2 +- .../NativeInterop/SocketAddress.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 4 +- src/Microsoft.Net.Server/Project.json | 40 ++++++++ .../Properties/AssemblyInfo.cs | 4 +- .../RequestProcessing/BoundaryType.cs | 2 +- .../RequestProcessing/ClientCertLoader.cs | 6 +- .../RequestProcessing/HeaderEncoding.cs | 2 +- .../RequestProcessing/HttpKnownHeaderNames.cs | 2 +- .../RequestProcessing/HttpReasonPhrase.cs | 2 +- .../RequestProcessing/HttpStatusCode.cs | 2 +- .../RequestProcessing/NativeRequestContext.cs | 2 +- .../RequestProcessing/OpaqueStream.cs | 2 +- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestContext.cs | 11 ++- .../RequestHeaders.Generated.cs | 2 +- .../RequestHeaders.Generated.tt | 2 +- .../RequestProcessing/RequestHeaders.cs | 2 +- .../RequestProcessing/RequestStream.cs | 6 +- .../RequestProcessing/RequestUriBuilder.cs | 2 +- .../RequestProcessing/Response.cs | 8 +- .../RequestProcessing/ResponseStream.cs | 10 +- .../ResponseStreamAsyncResult.cs | 2 +- .../RequestProcessing/SslStatus.cs | 2 +- .../Resources.Designer.cs | 2 +- .../Resources.resx | 0 .../TimeoutManager.cs | 8 +- .../UrlPrefix.cs | 2 +- .../ValidationHelper.cs | 2 +- .../WebListener.cs} | 12 +-- .../WebListenerException.cs | 2 +- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 0 .../SafeHandleZeroOrMinusOneIsInvalid.cs | 0 .../fx/System/Diagnostics/TraceEventType.cs | 0 .../fx/System/ExternDll.cs | 0 .../InteropServices/ExternalException.cs | 0 .../fx/System/SafeNativeMethods.cs | 0 .../ExtendedProtection/ChannelBinding.cs | 0 .../AuthenticationTests.cs | 1 + .../RequestTests.cs | 1 + .../ServerTests.cs | 1 + .../Utilities.cs | 1 + .../project.json | 1 + 85 files changed, 374 insertions(+), 239 deletions(-) delete mode 100644 src/Microsoft.AspNet.Security.Windows/Properties/AssemblyInfo.cs rename src/Microsoft.AspNet.Server.WebListener/{fx => }/AssemblyNeutralAttribute.cs (100%) rename src/Microsoft.AspNet.Server.WebListener/{RequestProcessing => }/FeatureContext.cs (99%) rename src/Microsoft.AspNet.Server.WebListener/{WebListenerWrapper.cs => MessagePump.cs} (92%) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/AsyncAcceptContext.cs (96%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/AuthenticationManager.cs (96%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/AuthenticationTypes.cs (87%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/Constants.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/CustomDictionary.xml (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/DictionaryExtensions.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/GlobalSuppressions.cs (100%) create mode 100644 src/Microsoft.Net.Server/Helpers.cs create mode 100644 src/Microsoft.Net.Server/LogHelper.cs create mode 100644 src/Microsoft.Net.Server/Microsoft.Net.Server.kproj rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/AddressFamily.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/ComNetOS.cs (93%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/ContextAttribute.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/HttpRequestQueueV2Handle.cs (94%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/HttpServerSessionHandle.cs (97%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/HttpSysRequestHeader.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/HttpSysResponseHeader.cs (97%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/HttpSysSettings.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/IntPtrHelper.cs (92%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/NclUtilities.cs (93%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SSPIHandle.cs (95%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SafeLoadLibrary.cs (96%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SafeLocalFree.cs (96%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SafeLocalFreeChannelBinding.cs (96%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SafeLocalMemHandle.cs (94%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SafeNativeOverlapped.cs (97%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SchProtocols.cs (97%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SecurityStatus.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/SocketAddress.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/NativeInterop/UnsafeNativeMethods.cs (99%) create mode 100644 src/Microsoft.Net.Server/Project.json rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/Properties/AssemblyInfo.cs (92%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/BoundaryType.cs (91%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/ClientCertLoader.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/HeaderEncoding.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/HttpKnownHeaderNames.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/HttpReasonPhrase.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/HttpStatusCode.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/NativeRequestContext.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/OpaqueStream.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/Request.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/RequestContext.cs (97%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/RequestHeaders.Generated.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/RequestHeaders.Generated.tt (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/RequestHeaders.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/RequestStream.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/RequestUriBuilder.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/Response.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/ResponseStream.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/ResponseStreamAsyncResult.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/RequestProcessing/SslStatus.cs (89%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/Resources.Designer.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/Resources.resx (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/TimeoutManager.cs (98%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/UrlPrefix.cs (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/ValidationHelper.cs (97%) rename src/{Microsoft.AspNet.Server.WebListener/OwinWebListener.cs => Microsoft.Net.Server/WebListener.cs} (99%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/WebListenerException.cs (96%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/fx/System/Diagnostics/TraceEventType.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/fx/System/ExternDll.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/fx/System/Runtime/InteropServices/ExternalException.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/fx/System/SafeNativeMethods.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.Net.Server}/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs (100%) diff --git a/WebListener.sln b/WebListener.sln index fc4110ba94..e2a7a67d0b 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -11,7 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E183C826-1 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A1E31E3-2794-4CA3-B8E2-253E96BDE514}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.kproj", "{3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Server", "src\Microsoft.Net.Server\Microsoft.Net.Server.kproj", "{3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\HelloWorld\HelloWorld.kproj", "{6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}" EndProject @@ -23,6 +23,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.WebSockets EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj", "{4492FF4C-9032-411D-853F-46B01755E504}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.kproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -103,6 +105,16 @@ Global {4492FF4C-9032-411D-853F-46B01755E504}.Release|Mixed Platforms.Build.0 = Release|x86 {4492FF4C-9032-411D-853F-46B01755E504}.Release|x86.ActiveCfg = Release|x86 {4492FF4C-9032-411D-853F-46B01755E504}.Release|x86.Build.0 = Release|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Any CPU.ActiveCfg = Debug|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|x86.ActiveCfg = Debug|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|x86.Build.0 = Debug|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Any CPU.ActiveCfg = Release|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.Build.0 = Release|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|x86.ActiveCfg = Release|x86 + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -115,5 +127,6 @@ Global {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {4492FF4C-9032-411D-853F-46B01755E504} = {E183C826-1360-4DFF-9994-F33CED5C8525} + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} EndGlobalSection EndGlobal diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 829908c001..6c44c812dd 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -1,7 +1,7 @@ using System; using System.Text; -using Microsoft.AspNet.Server.WebListener; +using Microsoft.Net.Server; namespace HelloWorld { @@ -9,7 +9,7 @@ namespace HelloWorld { public static void Main(string[] args) { - using (OwinWebListener listener = new OwinWebListener()) + using (WebListener listener = new WebListener()) { listener.UrlPrefixes.Add(UrlPrefix.Create("http://localhost:8080")); listener.Start(); diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 123a203698..5dd850e16e 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,7 +1,7 @@ { "version" : "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Server.WebListener" : "" + "Microsoft.Net.Server" : "" }, "configurations": { "net45": { }, diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 163ce335a6..b76a42a74f 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -1,5 +1,6 @@ using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Server.WebListener; +using Microsoft.Net.Server; namespace SelfHostServer { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index cb620bf621..3bf4abed6e 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -3,6 +3,7 @@ "dependencies": { "Microsoft.AspNet.Abstractions": "0.1-alpha-*", "Microsoft.AspNet.Hosting": "0.1-alpha-*", + "Microsoft.Net.Server": "", "Microsoft.AspNet.Server.WebListener": "" }, "commands": { "web": "Microsoft.AspNet.Hosting server.name=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001" }, diff --git a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj index 99d381529a..8f9815d39d 100644 --- a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj +++ b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj @@ -66,7 +66,6 @@ - diff --git a/src/Microsoft.AspNet.Security.Windows/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Security.Windows/Properties/AssemblyInfo.cs deleted file mode 100644 index 501727a48a..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,42 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Microsoft.AspNet.Security.Windows")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.AspNet.Security.Windows")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("1f471909-581f-4060-a147-430891e9c3c1")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.5")] -[assembly: AssemblyVersion("0.5")] -[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/AssemblyNeutralAttribute.cs b/src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/fx/AssemblyNeutralAttribute.cs rename to src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs rename to src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index b52beb029f..727fff3423 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.HttpFeature; +using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener { diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs similarity index 92% rename from src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs rename to src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index e274221a13..dcde3d3e8e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -3,16 +3,17 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Logging; +using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener { using AppFunc = Func; - internal class WebListenerWrapper : IDisposable + internal class MessagePump : IDisposable { private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; - private readonly OwinWebListener _listener; + private readonly Microsoft.Net.Server.WebListener _listener; private readonly ILogger _logger; private AppFunc _appFunc; @@ -23,17 +24,17 @@ namespace Microsoft.AspNet.Server.WebListener // TODO: private IDictionary _capabilities; - internal WebListenerWrapper(OwinWebListener listener, ILoggerFactory loggerFactory) + internal MessagePump(Microsoft.Net.Server.WebListener listener, ILoggerFactory loggerFactory) { Contract.Assert(listener != null); _listener = listener; - _logger = LogHelper.CreateLogger(loggerFactory, typeof(WebListenerWrapper)); + _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); _processRequest = new Action(ProcessRequestAsync); _maxAccepts = DefaultMaxAccepts; } - internal OwinWebListener Listener + internal Microsoft.Net.Server.WebListener Listener { get { return _listener; } } @@ -127,7 +128,7 @@ namespace Microsoft.AspNet.Server.WebListener { FeatureContext featureContext = new FeatureContext(requestContext); await _appFunc(featureContext.Features).SupressContext(); - await requestContext.ProcessResponseAsync().SupressContext(); + // TODO: WebSocket/Opaque upgrade - await requestContext.ProcessResponseAsync().SupressContext(); } catch (Exception ex) { diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj index 0547c1e84c..2114c166fd 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -6,9 +6,8 @@ - 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 + b9f45f9d-d206-47f0-8e5f-54ce2f0bdf92 Library - net45 @@ -18,78 +17,16 @@ 2.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index b0d1b819c4..f6447300cd 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -25,6 +25,7 @@ using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.ConfigurationModel; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Logging; +using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener { @@ -49,9 +50,9 @@ namespace Microsoft.AspNet.Server.WebListener [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] public IServerInformation Initialize(IConfiguration configuration) { - OwinWebListener listener = new OwinWebListener(); + Microsoft.Net.Server.WebListener listener = new Microsoft.Net.Server.WebListener(); ParseAddresses(configuration, listener); - return new ServerInformation(new WebListenerWrapper(listener, _loggerFactory)); + return new ServerInformation(new MessagePump(listener, _loggerFactory)); } /// @@ -78,11 +79,11 @@ namespace Microsoft.AspNet.Server.WebListener // TODO: var capabilities = new Dictionary(); - serverInfo.Wrapper.Start(app); - return serverInfo.Wrapper; + serverInfo.MessagePump.Start(app); + return serverInfo.MessagePump; } - private void ParseAddresses(IConfiguration config, OwinWebListener listener) + private void ParseAddresses(IConfiguration config, Microsoft.Net.Server.WebListener listener) { // TODO: Key format? string urls; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs index 6e514819c4..b3e4d9bfca 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNet.Server.WebListener { public class ServerInformation : IServerInformation { - private WebListenerWrapper _webListenerWrapper; + private MessagePump _messagePump; - internal ServerInformation(WebListenerWrapper webListenerWrapper) + internal ServerInformation(MessagePump messagePump) { - _webListenerWrapper = webListenerWrapper; + _messagePump = messagePump; } - internal WebListenerWrapper Wrapper + internal MessagePump MessagePump { - get { return _webListenerWrapper; } + get { return _messagePump; } } // Microsoft.AspNet.Server.WebListener @@ -23,15 +23,15 @@ namespace Microsoft.AspNet.Server.WebListener get { return GetType().GetTypeInfo().Assembly.GetName().Name; } } - public OwinWebListener Listener + public Microsoft.Net.Server.WebListener Listener { - get { return _webListenerWrapper.Listener; } + get { return _messagePump.Listener; } } public int MaxAccepts { - get { return _webListenerWrapper.MaxAccepts; } - set { _webListenerWrapper.MaxAccepts = value; } + get { return _messagePump.MaxAccepts; } + set { _messagePump.MaxAccepts = value; } } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs deleted file mode 100644 index d428778aad..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/fx/IServerFactory.cs +++ /dev/null @@ -1,16 +0,0 @@ -/* TODO: Take a temp dependency on Ms.Aspnet.Hosting until AssemblyNeutral gets fixed. -using System; -using System.Threading.Tasks; -using Microsoft.AspNet.Abstractions; -using Microsoft.AspNet.ConfigurationModel; - -namespace Microsoft.AspNet.Hosting.Server -{ - // TODO: [AssemblyNeutral] - public interface IServerFactory - { - IServerInformation Initialize(IConfiguration configuration); - IDisposable Start(IServerInformation serverInformation, Func application); - } -} -*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 82efe0ab48..ddf651ba54 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,6 +1,7 @@ -{ +{ "version": "0.1-alpha-*", "dependencies": { + "Microsoft.Net.Server" : "", "Microsoft.AspNet.Abstractions": "0.1-alpha-*", "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", diff --git a/src/Microsoft.AspNet.Server.WebListener/AsyncAcceptContext.cs b/src/Microsoft.Net.Server/AsyncAcceptContext.cs similarity index 96% rename from src/Microsoft.AspNet.Server.WebListener/AsyncAcceptContext.cs rename to src/Microsoft.Net.Server/AsyncAcceptContext.cs index a929f8a854..c21725ff3b 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Server/AsyncAcceptContext.cs @@ -10,17 +10,17 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal unsafe class AsyncAcceptContext : IAsyncResult, IDisposable { internal static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(IOWaitCallback); private TaskCompletionSource _tcs; - private OwinWebListener _server; + private WebListener _server; private NativeRequestContext _nativeRequestContext; - internal AsyncAcceptContext(OwinWebListener server) + internal AsyncAcceptContext(WebListener server) { _server = server; _tcs = new TaskCompletionSource(); @@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - private OwinWebListener Server + private WebListener Server { get { @@ -66,7 +66,7 @@ namespace Microsoft.AspNet.Server.WebListener } else { - OwinWebListener server = asyncResult.Server; + WebListener server = asyncResult.Server; if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { // at this point we have received an unmanaged HTTP_REQUEST and memoryBlob @@ -174,7 +174,7 @@ namespace Microsoft.AspNet.Server.WebListener retry = true; } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS - && OwinWebListener.SkipIOCPCallbackOnSuccess) + && WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. IOCompleted(this, statusCode, bytesTransferred); diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationManager.cs b/src/Microsoft.Net.Server/AuthenticationManager.cs similarity index 96% rename from src/Microsoft.AspNet.Server.WebListener/AuthenticationManager.cs rename to src/Microsoft.Net.Server/AuthenticationManager.cs index 9fa737049a..396dc6ec4c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationManager.cs +++ b/src/Microsoft.Net.Server/AuthenticationManager.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // See the native HTTP_SERVER_AUTHENTICATION_INFO structure documentation for additional information. // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364638(v=vs.85).aspx @@ -27,12 +27,12 @@ namespace Microsoft.AspNet.Server.WebListener Marshal.SizeOf(); #endif - private OwinWebListener _server; + private WebListener _server; AuthenticationType _authTypes; - internal AuthenticationManager(OwinWebListener context) + internal AuthenticationManager(WebListener listener) { - _server = context; + _server = listener; _authTypes = AuthenticationType.None; } diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationTypes.cs b/src/Microsoft.Net.Server/AuthenticationTypes.cs similarity index 87% rename from src/Microsoft.AspNet.Server.WebListener/AuthenticationTypes.cs rename to src/Microsoft.Net.Server/AuthenticationTypes.cs index 2e47212706..3d27938324 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationTypes.cs +++ b/src/Microsoft.Net.Server/AuthenticationTypes.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { [Flags] public enum AuthenticationType diff --git a/src/Microsoft.AspNet.Server.WebListener/Constants.cs b/src/Microsoft.Net.Server/Constants.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/Constants.cs rename to src/Microsoft.Net.Server/Constants.cs index 53e3325471..0c0ec42840 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Constants.cs +++ b/src/Microsoft.Net.Server/Constants.cs @@ -6,7 +6,7 @@ using System; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class Constants { diff --git a/src/Microsoft.AspNet.Server.WebListener/CustomDictionary.xml b/src/Microsoft.Net.Server/CustomDictionary.xml similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/CustomDictionary.xml rename to src/Microsoft.Net.Server/CustomDictionary.xml diff --git a/src/Microsoft.AspNet.Server.WebListener/DictionaryExtensions.cs b/src/Microsoft.Net.Server/DictionaryExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/DictionaryExtensions.cs rename to src/Microsoft.Net.Server/DictionaryExtensions.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/GlobalSuppressions.cs b/src/Microsoft.Net.Server/GlobalSuppressions.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/GlobalSuppressions.cs rename to src/Microsoft.Net.Server/GlobalSuppressions.cs diff --git a/src/Microsoft.Net.Server/Helpers.cs b/src/Microsoft.Net.Server/Helpers.cs new file mode 100644 index 0000000000..2331998246 --- /dev/null +++ b/src/Microsoft.Net.Server/Helpers.cs @@ -0,0 +1,29 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace Microsoft.Net.Server +{ + internal static class Helpers + { + internal static Task CompletedTask() + { + return Task.FromResult(null); + } + + internal static ConfiguredTaskAwaitable SupressContext(this Task task) + { + return task.ConfigureAwait(continueOnCapturedContext: false); + } + + internal static ConfiguredTaskAwaitable SupressContext(this Task task) + { + return task.ConfigureAwait(continueOnCapturedContext: false); + } + } +} diff --git a/src/Microsoft.Net.Server/LogHelper.cs b/src/Microsoft.Net.Server/LogHelper.cs new file mode 100644 index 0000000000..611317e3d5 --- /dev/null +++ b/src/Microsoft.Net.Server/LogHelper.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.Globalization; +using Microsoft.AspNet.Logging; + +namespace Microsoft.Net.Server +{ + internal static class LogHelper + { + internal static ILogger CreateLogger(ILoggerFactory factory, Type type) + { + if (factory == null) + { + return null; + } + + return factory.Create(type.FullName); + } + + internal static void LogInfo(ILogger logger, string data) + { + if (logger == null) + { + Debug.WriteLine(data); + } + else + { + logger.WriteInformation(data); + } + } + + internal static void LogVerbose(ILogger logger, string data) + { + if (logger == null) + { + Debug.WriteLine(data); + } + else + { + logger.WriteVerbose(data); + } + } + + internal static void LogException(ILogger logger, string location, Exception exception) + { + if (logger == null) + { + Debug.WriteLine(exception); + } + else + { + logger.WriteError(location, exception); + } + } + + internal static void LogError(ILogger logger, string location, string message) + { + if (logger == null) + { + Debug.WriteLine(message); + } + else + { + logger.WriteError(location + "; " + message); + } + } + } +} diff --git a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj new file mode 100644 index 0000000000..1599915ded --- /dev/null +++ b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj @@ -0,0 +1,89 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 + Library + net45 + + + + + + + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/AddressFamily.cs b/src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/AddressFamily.cs rename to src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs index 5f78516900..5bb16bcb69 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/AddressFamily.cs +++ b/src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs @@ -4,7 +4,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { /// /// diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs similarity index 93% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/ComNetOS.cs rename to src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs index 80e2719065..ff134adfb4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs @@ -6,7 +6,7 @@ using System; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class ComNetOS { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ContextAttribute.cs b/src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/ContextAttribute.cs rename to src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs index a3440bc7a3..7dac25d72a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/ContextAttribute.cs +++ b/src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs @@ -4,7 +4,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal enum ContextAttribute { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs similarity index 94% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpRequestQueueV2Handle.cs rename to src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs index ad9ae1d391..8538bf8989 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpRequestQueueV2Handle.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs @@ -6,7 +6,7 @@ using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // This class is a wrapper for Http.sys V2 request queue handle. internal sealed class HttpRequestQueueV2Handle : SafeHandleZeroOrMinusOneIsInvalid diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs similarity index 97% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpServerSessionHandle.cs rename to src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs index 65c0506f5c..ccec530d0b 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpServerSessionHandle.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs @@ -8,7 +8,7 @@ using System; using System.Threading; using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal sealed class HttpServerSessionHandle : CriticalHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysRequestHeader.cs b/src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysRequestHeader.cs rename to src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs index 1202ab2c80..5779ffcbb5 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysRequestHeader.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs @@ -4,7 +4,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal enum HttpSysRequestHeader { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysResponseHeader.cs b/src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs similarity index 97% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysResponseHeader.cs rename to src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs index 0c7707e943..a48727e520 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysResponseHeader.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs @@ -4,7 +4,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal enum HttpSysResponseHeader { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysSettings.cs rename to src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs index 98067e6fd6..1b7fa89c13 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs @@ -13,7 +13,7 @@ using System.Security; using Microsoft.Win32; #endif -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class HttpSysSettings { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/IntPtrHelper.cs b/src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs similarity index 92% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/IntPtrHelper.cs rename to src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs index 87ee72ce34..a319d629fd 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/IntPtrHelper.cs +++ b/src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs @@ -6,7 +6,7 @@ using System; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class IntPtrHelper { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs similarity index 93% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/NclUtilities.cs rename to src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs index 4e74a95560..c91d2f341d 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs @@ -6,7 +6,7 @@ using System; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class NclUtilities { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SSPIHandle.cs b/src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs similarity index 95% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SSPIHandle.cs rename to src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs index 6089860776..3e9d3bb063 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SSPIHandle.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs @@ -7,7 +7,7 @@ using System; using System.Runtime.InteropServices; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct SSPIHandle diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs similarity index 96% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLoadLibrary.cs rename to src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs index 998fbe014a..fa057da396 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLoadLibrary.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs @@ -6,7 +6,7 @@ using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFree.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs similarity index 96% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFree.cs rename to src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs index ad35b83ff0..91e9e953c3 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFree.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs @@ -7,7 +7,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFreeChannelBinding.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs similarity index 96% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFreeChannelBinding.cs rename to src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs index 66124161ca..cfa8b494fb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalFreeChannelBinding.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -7,7 +7,7 @@ using System; using System.Security.Authentication.ExtendedProtection; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal class SafeLocalFreeChannelBinding : ChannelBinding { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalMemHandle.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs similarity index 94% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalMemHandle.cs rename to src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs index 6bc76f512f..0a183236b5 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeLocalMemHandle.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs @@ -7,7 +7,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs similarity index 97% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeNativeOverlapped.cs rename to src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs index c36466ec84..4341285b03 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs @@ -8,7 +8,7 @@ using System; using System.Runtime.InteropServices; using System.Threading; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal class SafeNativeOverlapped : SafeHandle { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SchProtocols.cs b/src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs similarity index 97% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SchProtocols.cs rename to src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs index be1d240cd2..f02fd764fd 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SchProtocols.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs @@ -4,7 +4,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { using System; using System.Globalization; diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SecurityStatus.cs b/src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SecurityStatus.cs rename to src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs index 294fa1d863..f614cbf150 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SecurityStatus.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs @@ -4,7 +4,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal enum SecurityStatus { diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs b/src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs rename to src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs index 78b52c13c7..51d3f9474e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/SocketAddress.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs @@ -11,7 +11,7 @@ using System.Globalization; using System.Net; using System.Text; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // a little perf app measured these times when comparing the internal // buffer implemented as a managed byte[] or unmanaged memory IntPtr diff --git a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs rename to src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs index 5591fd2068..eccaf869b0 100644 --- a/src/Microsoft.AspNet.Server.WebListener/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class UnsafeNclNativeMethods { @@ -63,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] internal static extern unsafe uint HttpCreateRequestQueue(HttpApi.HTTPAPI_VERSION version, string pName, - Microsoft.AspNet.Server.WebListener.UnsafeNclNativeMethods.SECURITY_ATTRIBUTES pSecurityAttributes, uint flags, out HttpRequestQueueV2Handle pReqQueueHandle); + Microsoft.Net.Server.UnsafeNclNativeMethods.SECURITY_ATTRIBUTES pSecurityAttributes, uint flags, out HttpRequestQueueV2Handle pReqQueueHandle); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); diff --git a/src/Microsoft.Net.Server/Project.json b/src/Microsoft.Net.Server/Project.json new file mode 100644 index 0000000000..9eb34075ee --- /dev/null +++ b/src/Microsoft.Net.Server/Project.json @@ -0,0 +1,40 @@ +{ + "version": "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Logging": "0.1-alpha-*" + }, + "compilationOptions": { + "allowUnsafe": true + }, + "configurations": { + "net45": {}, + "k10": { + "dependencies": { + "System.Collections": "4.0.0.0", + "System.Collections.Concurrent": "4.0.0.0", + "System.Diagnostics.Contracts": "4.0.0.0", + "System.Diagnostics.Debug": "4.0.10.0", + "System.Diagnostics.Tools": "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO": "4.0.0.0", + "System.IO.FileSystem": "4.0.0.0", + "System.IO.FileSystem.Primitives": "4.0.0.0", + "System.Linq": "4.0.0.0", + "System.Reflection": "4.0.10.0", + "System.Resources.ResourceManager": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "System.Runtime.Extensions": "4.0.10.0", + "System.Runtime.InteropServices": "4.0.20.0", + "System.Runtime.Handles": "4.0.0.0", + "System.Security.Principal": "4.0.0.0", + "System.Text.Encoding": "4.0.20.0", + "System.Text.Encoding.Extensions": "4.0.10.0", + "System.Threading": "4.0.0.0", + "System.Threading.Overlapped": "4.0.0.0", + "System.Threading.Tasks": "4.0.10.0", + "System.Threading.ThreadPool": "4.0.10.0", + "Microsoft.Win32.Primitives": "4.0.0.0" + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs similarity index 92% rename from src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs rename to src/Microsoft.Net.Server/Properties/AssemblyInfo.cs index ed361b4f1c..5713f21df4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs @@ -12,11 +12,11 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Microsoft.AspNet.Server.WebListener")] +[assembly: AssemblyTitle("Microsoft.Net.Server")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.AspNet.Server.WebListener")] +[assembly: AssemblyProduct("Microsoft.Net.Server")] [assembly: AssemblyCopyright("Copyright © 2012")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs b/src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs similarity index 91% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs rename to src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs index d6f4fd2007..31357ce6b6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs @@ -4,7 +4,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal enum BoundaryType { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs rename to src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs index d5efd0b12e..0600ad3454 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs @@ -14,7 +14,7 @@ using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // This class is used to load the client certificate on-demand. Because client certs are optional, all // failures are handled internally and reported via ClientCertException or ClientCertError. @@ -177,7 +177,7 @@ namespace Microsoft.AspNet.Server.WebListener Complete(0, null); } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - OwinWebListener.SkipIOCPCallbackOnSuccess) + WebListener.SkipIOCPCallbackOnSuccess) { IOCompleted(statusCode, bytesReceived); } @@ -243,7 +243,7 @@ namespace Microsoft.AspNet.Server.WebListener asyncResult._overlapped); if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING || - (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && !OwinWebListener.SkipIOCPCallbackOnSuccess)) + (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && !WebListener.SkipIOCPCallbackOnSuccess)) { return; } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HeaderEncoding.cs b/src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HeaderEncoding.cs rename to src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs index 24a8df80ff..148985426a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HeaderEncoding.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // we use this static class as a helper class to encode/decode HTTP headers. // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpKnownHeaderNames.cs b/src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpKnownHeaderNames.cs rename to src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs index 9885de2fcd..788477f478 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpKnownHeaderNames.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs @@ -4,7 +4,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class HttpKnownHeaderNames { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpReasonPhrase.cs b/src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpReasonPhrase.cs rename to src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs index 27370832ff..40836a36ea 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpReasonPhrase.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs @@ -4,7 +4,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class HttpReasonPhrase { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpStatusCode.cs b/src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpStatusCode.cs rename to src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs index 88e6fe4b18..83993f3065 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/HttpStatusCode.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs @@ -4,7 +4,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // Redirect Status code numbers that need to be defined. diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NativeRequestContext.cs rename to src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs index 8ab4f029cb..15e99f7343 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs @@ -9,7 +9,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal unsafe class NativeRequestContext : IDisposable { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/OpaqueStream.cs rename to src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs index 6238d9185d..2016976aa0 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs @@ -9,7 +9,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // A duplex wrapper around RequestStream and ResponseStream. // TODO: Consider merging RequestStream and ResponseStream instead. diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.Net.Server/RequestProcessing/Request.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs rename to src/Microsoft.Net.Server/RequestProcessing/Request.cs index 5b7875cd08..67471d70d5 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Request.cs @@ -15,7 +15,7 @@ using System.Security.Principal; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { public sealed class Request { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs similarity index 97% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs rename to src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index 1325eaed14..0546cf349a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -13,13 +13,13 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Logging; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { using OpaqueFunc = Func, Task>; public sealed class RequestContext : IDisposable { - private OwinWebListener _server; + private WebListener _server; private Request _request; private Response _response; private NativeRequestContext _memoryBlob; @@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Server.WebListener private CancellationTokenRegistration? _disconnectRegistration; private CancellationToken? _disconnectToken; - internal RequestContext(OwinWebListener httpListener, NativeRequestContext memoryBlob) + internal RequestContext(WebListener httpListener, NativeRequestContext memoryBlob) { // TODO: Verbose log _server = httpListener; @@ -81,7 +81,7 @@ namespace Microsoft.AspNet.Server.WebListener context.Abort(); } - internal OwinWebListener Server + internal WebListener Server { get { @@ -194,7 +194,7 @@ namespace Microsoft.AspNet.Server.WebListener // RequestQueueHandle may have been closed } } - + /* internal void OpaqueUpgrade(IDictionary parameters, OpaqueFunc callback) { // Parameters are ignored for now @@ -245,5 +245,6 @@ namespace Microsoft.AspNet.Server.WebListener return opaqueEnv; } + */ } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.cs rename to src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs index 2e2df172c3..4ec5271c51 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs @@ -13,7 +13,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class RequestHeaders diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.tt b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.tt similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.tt rename to src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.tt index 2b339e4640..6545fffe44 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.Generated.tt +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.tt @@ -69,7 +69,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Owin.Host.WebListener +namespace Microsoft.Net.Server { [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class RequestHeaders diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.cs rename to src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs index 9e43ab86e5..43b9fb1e7f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs @@ -23,7 +23,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal partial class RequestHeaders : IDictionary { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs rename to src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs index e39f146c67..312dde4152 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs @@ -11,7 +11,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal class RequestStream : Stream { @@ -258,7 +258,7 @@ namespace Microsoft.AspNet.Server.WebListener } } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - OwinWebListener.SkipIOCPCallbackOnSuccess) + WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode, bytesReturned); @@ -374,7 +374,7 @@ namespace Microsoft.AspNet.Server.WebListener } } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - OwinWebListener.SkipIOCPCallbackOnSuccess) + WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.Dispose(); diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestUriBuilder.cs rename to src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs index 697934fc93..4a9bb518de 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs @@ -10,7 +10,7 @@ using System.Diagnostics; using System.Globalization; using System.Text; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // We don't use the cooked URL because http.sys unescapes all percent-encoded values. However, // we also can't just use the raw Uri, since http.sys supports not only Utf-8, but also ANSI/DBCS and diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs b/src/Microsoft.Net.Server/RequestProcessing/Response.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs rename to src/Microsoft.Net.Server/RequestProcessing/Response.cs index 2364e2a777..dd9738e443 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Response.cs @@ -14,7 +14,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { public sealed unsafe class Response { @@ -288,7 +288,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal bool SentHeaders + public bool SentHeaders { get { @@ -404,7 +404,7 @@ namespace Microsoft.AspNet.Server.WebListener if (asyncResult != null && statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - OwinWebListener.SkipIOCPCallbackOnSuccess) + WebListener.SkipIOCPCallbackOnSuccess) { asyncResult.BytesSent = bytesSent; // The caller will invoke IOCompleted @@ -431,7 +431,7 @@ namespace Microsoft.AspNet.Server.WebListener if (asyncResult != null && statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - OwinWebListener.SkipIOCPCallbackOnSuccess) + WebListener.SkipIOCPCallbackOnSuccess) { asyncResult.BytesSent = bytesSent; // The caller will invoke IOCompleted diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs rename to src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs index 8d49f85ca3..21b38033e9 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs @@ -12,7 +12,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal class ResponseStream : Stream { @@ -133,7 +133,7 @@ namespace Microsoft.AspNet.Server.WebListener statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); } - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode); @@ -425,7 +425,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode, bytesSent); @@ -565,7 +565,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode, bytesSent); @@ -680,7 +680,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode, bytesSent); diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs rename to src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 42b81228f8..a6c45b27f4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -11,7 +11,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal unsafe class ResponseStreamAsyncResult : IAsyncResult, IDisposable { diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/SslStatus.cs b/src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs similarity index 89% rename from src/Microsoft.AspNet.Server.WebListener/RequestProcessing/SslStatus.cs rename to src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs index 72118c2d46..cc4debcdaa 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/SslStatus.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs @@ -4,7 +4,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal enum SslStatus : byte { diff --git a/src/Microsoft.AspNet.Server.WebListener/Resources.Designer.cs b/src/Microsoft.Net.Server/Resources.Designer.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/Resources.Designer.cs rename to src/Microsoft.Net.Server/Resources.Designer.cs index aafe87fb8d..e0db3bdfbc 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Resources.Designer.cs +++ b/src/Microsoft.Net.Server/Resources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.AspNet.Server.WebListener { +namespace Microsoft.Net.Server { using System; diff --git a/src/Microsoft.AspNet.Server.WebListener/Resources.resx b/src/Microsoft.Net.Server/Resources.resx similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/Resources.resx rename to src/Microsoft.Net.Server/Resources.resx diff --git a/src/Microsoft.AspNet.Server.WebListener/TimeoutManager.cs b/src/Microsoft.Net.Server/TimeoutManager.cs similarity index 98% rename from src/Microsoft.AspNet.Server.WebListener/TimeoutManager.cs rename to src/Microsoft.Net.Server/TimeoutManager.cs index 9e74f6563a..b90c212758 100644 --- a/src/Microsoft.AspNet.Server.WebListener/TimeoutManager.cs +++ b/src/Microsoft.Net.Server/TimeoutManager.cs @@ -8,7 +8,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { // See the native HTTP_TIMEOUT_LIMIT_INFO structure documentation for additional information. // http://msdn.microsoft.com/en-us/library/aa364661.aspx @@ -25,13 +25,13 @@ namespace Microsoft.AspNet.Server.WebListener private static readonly int TimeoutLimitSize = Marshal.SizeOf(); #endif - private OwinWebListener _server; + private WebListener _server; private int[] _timeouts; private uint _minSendBytesPerSecond; - internal TimeoutManager(OwinWebListener context) + internal TimeoutManager(WebListener listener) { - _server = context; + _server = listener; // We have to maintain local state since we allow applications to set individual timeouts. Native Http // API for setting timeouts expects all timeout values in every call so we have remember timeout values diff --git a/src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs b/src/Microsoft.Net.Server/UrlPrefix.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs rename to src/Microsoft.Net.Server/UrlPrefix.cs index 7a6e36e1ee..96046033c8 100644 --- a/src/Microsoft.AspNet.Server.WebListener/UrlPrefix.cs +++ b/src/Microsoft.Net.Server/UrlPrefix.cs @@ -7,7 +7,7 @@ using System; using System.Globalization; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { public class UrlPrefix { diff --git a/src/Microsoft.AspNet.Server.WebListener/ValidationHelper.cs b/src/Microsoft.Net.Server/ValidationHelper.cs similarity index 97% rename from src/Microsoft.AspNet.Server.WebListener/ValidationHelper.cs rename to src/Microsoft.Net.Server/ValidationHelper.cs index 104e49e320..5e17218855 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ValidationHelper.cs +++ b/src/Microsoft.Net.Server/ValidationHelper.cs @@ -7,7 +7,7 @@ using System; using System.Globalization; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { internal static class ValidationHelper { diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.Net.Server/WebListener.cs similarity index 99% rename from src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs rename to src/Microsoft.Net.Server/WebListener.cs index bdb7a0ba83..1d72a75db7 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.Net.Server/WebListener.cs @@ -17,14 +17,14 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Logging; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { using AppFunc = Func; /// /// An HTTP server wrapping the Http.Sys APIs that accepts requests and passes them on to the given OWIN application. /// - public sealed class OwinWebListener : IDisposable + public sealed class WebListener : IDisposable { private const long DefaultRequestQueueLength = 1000; // Http.sys default. #if NET45 @@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Server.WebListener // The native request queue private long? _requestQueueLength; - public OwinWebListener() + public WebListener() { if (!UnsafeNclNativeMethods.HttpApi.Supported) { @@ -754,7 +754,7 @@ namespace Microsoft.AspNet.Server.WebListener return CancellationToken.None; } - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && OwinWebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. // TODO: return a canceled token? @@ -920,11 +920,11 @@ namespace Microsoft.AspNet.Server.WebListener private class ConnectionCancellation { - private readonly OwinWebListener _parent; + private readonly WebListener _parent; private volatile bool _initialized; // Must be volatile because initialization is synchronized private CancellationToken _cancellationToken; - public ConnectionCancellation(OwinWebListener parent) + public ConnectionCancellation(WebListener parent) { _parent = parent; } diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs b/src/Microsoft.Net.Server/WebListenerException.cs similarity index 96% rename from src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs rename to src/Microsoft.Net.Server/WebListenerException.cs index 63c5f1713e..11a5a2daed 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs +++ b/src/Microsoft.Net.Server/WebListenerException.cs @@ -9,7 +9,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.Net.Server { [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] public class WebListenerException : Win32Exception diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs rename to src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs rename to src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Server/fx/System/Diagnostics/TraceEventType.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/fx/System/Diagnostics/TraceEventType.cs rename to src/Microsoft.Net.Server/fx/System/Diagnostics/TraceEventType.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/ExternDll.cs b/src/Microsoft.Net.Server/fx/System/ExternDll.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/fx/System/ExternDll.cs rename to src/Microsoft.Net.Server/fx/System/ExternDll.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Server/fx/System/Runtime/InteropServices/ExternalException.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/fx/System/Runtime/InteropServices/ExternalException.cs rename to src/Microsoft.Net.Server/fx/System/Runtime/InteropServices/ExternalException.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Server/fx/System/SafeNativeMethods.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/fx/System/SafeNativeMethods.cs rename to src/Microsoft.Net.Server/fx/System/SafeNativeMethods.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs b/src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs rename to src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 893fc4c941..760a21c556 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; +using Microsoft.Net.Server; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 041665d0bb..fbbc621d3f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; +using Microsoft.Net.Server; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 5b8b79d68f..d6233e5c6d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; +using Microsoft.Net.Server; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index 57dab56d0c..d96ef5d45d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; +using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 76202da8df..4f6ab2edbd 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -10,6 +10,7 @@ "xunit.core": "2.0.0-aspnet-*", "xunit.execution": "2.0.0-aspnet-*", "Microsoft.AspNet.Server.WebListener" : "", + "Microsoft.Net.Server" : "", "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", From c8af9179272807c4ed8f739d16384e629b83a0bd Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 18 Apr 2014 09:19:37 -0700 Subject: [PATCH 033/597] Expose IPAddress, X509Certificate. --- src/Microsoft.Net.Server/Project.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Microsoft.Net.Server/Project.json b/src/Microsoft.Net.Server/Project.json index 9eb34075ee..c0aa89bb6a 100644 --- a/src/Microsoft.Net.Server/Project.json +++ b/src/Microsoft.Net.Server/Project.json @@ -20,12 +20,14 @@ "System.IO.FileSystem": "4.0.0.0", "System.IO.FileSystem.Primitives": "4.0.0.0", "System.Linq": "4.0.0.0", + "System.Net.Primitives": "4.0.10.0", "System.Reflection": "4.0.10.0", "System.Resources.ResourceManager": "4.0.0.0", "System.Runtime": "4.0.20.0", "System.Runtime.Extensions": "4.0.10.0", "System.Runtime.InteropServices": "4.0.20.0", "System.Runtime.Handles": "4.0.0.0", + "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", "System.Text.Encoding.Extensions": "4.0.10.0", From e2d80207274ea2e65c1cfe11c97d8deb2653f98f Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 28 Apr 2014 12:32:17 -0700 Subject: [PATCH 034/597] #20 - Enable SendFile on CoreClr. --- .../RequestProcessing/ResponseStreamAsyncResult.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs index a6c45b27f4..b6d045848c 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -119,9 +119,6 @@ namespace Microsoft.Net.Server #else _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. #endif -#if !NET45 - throw new NotImplementedException(); -#else long length = _fileStream.Length; // Expensive if (offset < 0 || offset > length) { @@ -189,7 +186,6 @@ namespace Microsoft.Net.Server _dataChunks[2].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(CRLF, 0); } } -#endif } internal ResponseStream ResponseStream From 8e23200fd2d3f6e22e74f2a1a6f8ba0f682c6eff Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 28 Apr 2014 14:54:33 -0700 Subject: [PATCH 035/597] #3 - Implement IHttpRequestLifetime --- .../FeatureContext.cs | 13 ++++++- .../RequestProcessing/RequestContext.cs | 38 ++++++++++++------- .../ServerTests.cs | 36 ++++++++++++++++-- 3 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 727fff3423..361a26face 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -11,7 +11,7 @@ using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener { - internal class FeatureContext : IHttpRequestInformation, IHttpConnection, IHttpResponseInformation, IHttpSendFile, IHttpTransportLayerSecurity + internal class FeatureContext : IHttpRequestInformation, IHttpConnection, IHttpResponseInformation, IHttpSendFile, IHttpTransportLayerSecurity, IHttpRequestLifetime { private RequestContext _requestContext; private FeatureCollection _features; @@ -66,6 +66,7 @@ namespace Microsoft.AspNet.Server.WebListener } _features.Add(typeof(IHttpResponseInformation), this); _features.Add(typeof(IHttpSendFile), this); + _features.Add(typeof(IHttpRequestLifetime), this); // TODO: // _environment.CallCancelled = _cts.Token; @@ -334,5 +335,15 @@ namespace Microsoft.AspNet.Server.WebListener { return Response.SendFileAsync(path, offset, length, cancellation); } + + public CancellationToken OnRequestAborted + { + get { return _requestContext.DisconnectToken; } + } + + public void Abort() + { + _requestContext.Abort(); + } } } diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index 0546cf349a..16ac300615 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -25,7 +25,7 @@ namespace Microsoft.Net.Server private NativeRequestContext _memoryBlob; private OpaqueFunc _opaqueCallback; private bool _disposed; - private CancellationTokenRegistration? _disconnectRegistration; + private CancellationTokenSource _requestAbortSource; private CancellationToken? _disconnectToken; internal RequestContext(WebListener httpListener, NativeRequestContext memoryBlob) @@ -63,24 +63,26 @@ namespace Microsoft.Net.Server { get { + // Create a new token per request, but link it to a single connection token. + // We need to be able to dispose of the registrations each request to prevent leaks. if (!_disconnectToken.HasValue) { - _disconnectToken = _server.RegisterForDisconnectNotification(this); - if (_disconnectToken.Value.CanBeCanceled) + var connectionDisconnectToken = _server.RegisterForDisconnectNotification(this); + + if (connectionDisconnectToken.CanBeCanceled) { - _disconnectRegistration = _disconnectToken.Value.Register(Cancel, this); + _requestAbortSource = CancellationTokenSource.CreateLinkedTokenSource(connectionDisconnectToken); + _disconnectToken = _requestAbortSource.Token; + } + else + { + _disconnectToken = CancellationToken.None; } } return _disconnectToken.Value; } } - private static void Cancel(object obj) - { - RequestContext context = (RequestContext)obj; - context.Abort(); - } - internal WebListener Server { get @@ -138,9 +140,9 @@ namespace Microsoft.Net.Server // TODO: Verbose log try { - if (_disconnectRegistration.HasValue) + if (_requestAbortSource != null) { - _disconnectRegistration.Value.Dispose(); + _requestAbortSource.Dispose(); } _response.Dispose(); } @@ -155,9 +157,17 @@ namespace Microsoft.Net.Server // May be called from Dispose() code path, don't check _disposed. // TODO: Verbose log _disposed = true; - if (_disconnectRegistration.HasValue) + if (_requestAbortSource != null) { - _disconnectRegistration.Value.Dispose(); + try + { + _requestAbortSource.Cancel(); + } + catch (Exception ex) + { + LogHelper.LogException(Logger, "Abort", ex); + } + _requestAbortSource.Dispose(); } ForceCancelRequest(RequestQueueHandle, _request.RequestId); _request.Dispose(); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index d6233e5c6d..9c7511aba3 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -147,7 +147,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.True(Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(2)), "Timed out"); } } - /* TODO: + [Fact] public async Task Server_ClientDisconnects_CallCancelled() { @@ -158,7 +158,8 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { - CancellationToken ct = env.Get("owin.CallCancelled"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + CancellationToken ct = httpContext.OnRequestAborted; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); ct.Register(() => canceled.Set()); @@ -180,7 +181,36 @@ namespace Microsoft.AspNet.Server.WebListener Assert.True(canceled.WaitOne(interval), "canceled"); } } - */ + + [Fact] + public async Task Server_Abort_CallCancelled() + { + TimeSpan interval = TimeSpan.FromSeconds(100); + ManualResetEvent received = new ManualResetEvent(false); + ManualResetEvent aborted = new ManualResetEvent(false); + ManualResetEvent canceled = new ManualResetEvent(false); + + using (Utilities.CreateHttpServer(env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + CancellationToken ct = httpContext.OnRequestAborted; + Assert.True(ct.CanBeCanceled, "CanBeCanceled"); + Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); + ct.Register(() => canceled.Set()); + received.Set(); + httpContext.Abort(); + Assert.True(canceled.WaitOne(interval), "Aborted"); + Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); + return Task.FromResult(0); + })) + { + using (Socket socket = await SendHungRequestAsync("GET", Address)) + { + Assert.True(received.WaitOne(interval), "Receive Timeout"); + Assert.Throws(() => socket.Receive(new byte[10])); + } + } + } [Fact] public async Task Server_SetQueueLimit_Success() From 7555b17d41735f43552e282de609ff84edd0263b Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 1 May 2014 15:37:23 -0700 Subject: [PATCH 036/597] Update filesystem dependencies. --- src/Microsoft.AspNet.Server.WebListener/project.json | 2 -- src/Microsoft.Net.Server/Project.json | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index ddf651ba54..ebd2c31782 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -23,8 +23,6 @@ "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", - "System.IO.FileSystem": "4.0.0.0", - "System.IO.FileSystem.Primitives": "4.0.0.0", "System.Linq": "4.0.0.0", "System.Reflection": "4.0.10.0", "System.Resources.ResourceManager": "4.0.0.0", diff --git a/src/Microsoft.Net.Server/Project.json b/src/Microsoft.Net.Server/Project.json index c0aa89bb6a..d948282b13 100644 --- a/src/Microsoft.Net.Server/Project.json +++ b/src/Microsoft.Net.Server/Project.json @@ -17,8 +17,8 @@ "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", - "System.IO.FileSystem": "4.0.0.0", - "System.IO.FileSystem.Primitives": "4.0.0.0", + "System.IO.FileSystem": "4.0.10.0", + "System.IO.FileSystem.Primitives": "4.0.20.0", "System.Linq": "4.0.0.0", "System.Net.Primitives": "4.0.10.0", "System.Reflection": "4.0.10.0", From 35fcc7a5791e1f0eff0aae6483be9bfb034f6cd3 Mon Sep 17 00:00:00 2001 From: anpete Date: Thu, 1 May 2014 17:43:17 -0700 Subject: [PATCH 037/597] Update file headers --- samples/HelloWorld/Program.cs | 16 +++++++++++++ .../SelfHostServer/Properties/AssemblyInfo.cs | 17 ++++++++++++++ samples/SelfHostServer/Startup.cs | 19 +++++++++++++++- samples/TestClient/Program.cs | 19 +++++++++++++++- samples/TestClient/Properties/AssemblyInfo.cs | 17 ++++++++++++++ .../AuthTypes.cs | 19 +++++++++++++++- .../ComNetOS.cs | 19 +++++++++++++++- .../Constants.cs | 19 +++++++++++++++- .../DictionaryExtensions.cs | 19 +++++++++++++++- .../DigestCache.cs | 19 +++++++++++++++- .../DisconnectAsyncResult.cs | 19 +++++++++++++++- .../HeaderEncoding.cs | 17 ++++++++++++++ .../HttpKnownHeaderNames.cs | 19 +++++++++++++++- .../HttpStatusCode.cs | 17 ++++++++++++++ .../Legacy/CaseInsinsitiveAscii.cs | 19 +++++++++++++++- .../Legacy/GlobalLog.cs | 19 +++++++++++++++- .../Legacy/HttpListenerContext.cs | 17 ++++++++++++++ .../Legacy/Internal.cs | 17 ++++++++++++++ .../Legacy/Logging.cs | 17 ++++++++++++++ .../Legacy/LoggingObject.cs | 17 ++++++++++++++ .../Legacy/SR.cs | 19 +++++++++++++++- .../Legacy/ValidationHelper.cs | 19 +++++++++++++++- .../NTAuthentication.cs | 17 ++++++++++++++ .../NativeInterop/AuthIdentity.cs | 19 +++++++++++++++- .../NativeInterop/ContextFlags.cs | 19 +++++++++++++++- .../NativeInterop/NativeSSPI.cs | 17 ++++++++++++++ .../NativeInterop/SSPIAuthType.cs | 19 +++++++++++++++- .../NativeInterop/SSPIHandle.cs | 19 +++++++++++++++- .../NativeInterop/SSPISessionCache.cs | 17 ++++++++++++++ .../NativeInterop/SSPIWrapper.cs | 17 ++++++++++++++ .../NativeInterop/SafeCloseHandle.cs | 17 ++++++++++++++ .../NativeInterop/SafeCredentialReference.cs | 19 +++++++++++++++- .../NativeInterop/SafeDeleteContext.cs | 19 +++++++++++++++- .../NativeInterop/SafeFreeCertContext.cs | 19 +++++++++++++++- .../NativeInterop/SafeFreeContextBuffer.cs | 19 +++++++++++++++- .../SafeFreeContextBufferChannelBinding.cs | 19 +++++++++++++++- .../NativeInterop/SafeFreeCredentials.cs | 19 +++++++++++++++- .../NativeInterop/SafeLocalFree.cs | 19 +++++++++++++++- .../NativeInterop/SafeSspiAuthDataHandle.cs | 19 +++++++++++++++- .../NativeInterop/SchProtocols.cs | 19 +++++++++++++++- .../NativeInterop/SecSizes.cs | 19 +++++++++++++++- .../NativeInterop/SecurityBuffer.cs | 19 +++++++++++++++- .../NativeInterop/SecurityBufferDescriptor.cs | 19 +++++++++++++++- .../NativeInterop/SecurityPackageInfoClass.cs | 19 +++++++++++++++- .../NativeInterop/SslConnectionInfo.cs | 19 +++++++++++++++- .../NativeInterop/StreamSizes.cs | 19 +++++++++++++++- .../NativeInterop/UnsafeNativeMethods.cs | 17 ++++++++++++++ .../NegotiationInfoClass.cs | 19 +++++++++++++++- .../PrefixCollection.cs | 19 +++++++++++++++- .../PrefixEnumerator.cs | 17 ++++++++++++++ .../ServiceNameStore.cs | 19 +++++++++++++++- .../WindowsAuthMiddleware.cs | 17 ++++++++++++++ .../AssemblyNeutralAttribute.cs | 19 +++++++++++++++- .../FeatureContext.cs | 19 +++++++++++++++- .../Helpers.cs | 19 +++++++++++++++- .../LogHelper.cs | 19 +++++++++++++++- .../MessagePump.cs | 19 +++++++++++++++- .../ServerFactory.cs | 19 +++++++++++++++- .../ServerInformation.cs | 19 +++++++++++++++- src/Microsoft.AspNet.WebSockets/Constants.cs | 17 +++++++++++++- .../HttpKnownHeaderNames.cs | 17 ++++++++++++++ .../Legacy/HttpListenerContext.cs | 17 ++++++++++++++ .../Legacy/HttpListenerRequest.cs | 17 ++++++++++++++ src/Microsoft.AspNet.WebSockets/Legacy/SR.cs | 19 +++++++++++++++- .../WebSocketHttpListenerDuplexStream.cs | 17 ++++++++++++++ .../NativeInterop/SafeLoadLibrary.cs | 17 ++++++++++++++ .../NativeInterop/SafeNativeOverlapped.cs | 17 ++++++++++++++ .../NativeInterop/SafeWebSocketHandle.cs | 17 ++++++++++++++ .../NativeInterop/UnsafeNativeMethods.cs | 17 ++++++++++++++ .../OwinWebSocketWrapper.cs | 17 +++++++++++++- .../Properties/AssemblyInfo.cs | 17 ++++++++++++++ .../ServerWebSocket.cs | 17 ++++++++++++++ src/Microsoft.AspNet.WebSockets/WebSocket.cs | 17 ++++++++++++++ .../WebSocketBase.cs | 17 ++++++++++++++ .../WebSocketBuffer.cs | 17 ++++++++++++++ .../WebSocketCloseStatus.cs | 17 ++++++++++++++ .../WebSocketError.cs | 17 ++++++++++++++ .../WebSocketException.cs | 17 ++++++++++++++ .../WebSocketExtensions.cs | 19 +++++++++++++++- .../WebSocketHelpers.cs | 17 ++++++++++++++ .../WebSocketMessageType.cs | 17 ++++++++++++++ .../WebSocketMiddleware.cs | 19 +++++++++++++++- .../WebSocketReceiveResult.cs | 17 ++++++++++++++ .../WebSocketState.cs | 17 ++++++++++++++ .../SafeHandleZeroOrMinusOneIsInvalid.cs | 19 +++++++++++++++- .../fx/System/AccessViolationException.cs | 19 +++++++++++++++- .../System/ComponentModel/Win32Exception.cs | 19 +++++++++++++++- .../fx/System/ExternDll.cs | 19 +++++++++++++++- .../InteropServices/ExternalException.cs | 19 +++++++++++++++- .../fx/System/SafeNativeMethods.cs | 19 +++++++++++++++- .../fx/System/SystemException.cs | 19 +++++++++++++++- .../AsyncAcceptContext.cs | 17 ++++++++++++++ .../AuthenticationManager.cs | 19 +++++++++++++++- .../AuthenticationTypes.cs | 19 +++++++++++++++- src/Microsoft.Net.Server/Constants.cs | 19 +++++++++++++++- .../DictionaryExtensions.cs | 19 +++++++++++++++- .../GlobalSuppressions.cs | Bin 1926 -> 1636 bytes src/Microsoft.Net.Server/Helpers.cs | 19 +++++++++++++++- src/Microsoft.Net.Server/LogHelper.cs | 19 +++++++++++++++- .../NativeInterop/AddressFamily.cs | 19 +++++++++++++++- .../NativeInterop/ComNetOS.cs | 19 +++++++++++++++- .../NativeInterop/ContextAttribute.cs | 19 +++++++++++++++- .../NativeInterop/HttpRequestQueueV2Handle.cs | 17 ++++++++++++++ .../NativeInterop/HttpServerSessionHandle.cs | 19 +++++++++++++++- .../NativeInterop/HttpSysRequestHeader.cs | 17 ++++++++++++++ .../NativeInterop/HttpSysResponseHeader.cs | 17 ++++++++++++++ .../NativeInterop/HttpSysSettings.cs | 17 ++++++++++++++ .../NativeInterop/IntPtrHelper.cs | 17 ++++++++++++++ .../NativeInterop/NclUtilities.cs | 19 +++++++++++++++- .../NativeInterop/SSPIHandle.cs | 19 +++++++++++++++- .../NativeInterop/SafeLoadLibrary.cs | 19 +++++++++++++++- .../NativeInterop/SafeLocalFree.cs | 19 +++++++++++++++- .../SafeLocalFreeChannelBinding.cs | 19 +++++++++++++++- .../NativeInterop/SafeLocalMemHandle.cs | 19 +++++++++++++++- .../NativeInterop/SafeNativeOverlapped.cs | 19 +++++++++++++++- .../NativeInterop/SchProtocols.cs | 17 ++++++++++++++ .../NativeInterop/SecurityStatus.cs | 19 +++++++++++++++- .../NativeInterop/SocketAddress.cs | 17 ++++++++++++++ .../NativeInterop/UnsafeNativeMethods.cs | 17 ++++++++++++++ .../Properties/AssemblyInfo.cs | 17 ++++++++++++++ .../RequestProcessing/BoundaryType.cs | 19 +++++++++++++++- .../RequestProcessing/ClientCertLoader.cs | 19 +++++++++++++++- .../RequestProcessing/HeaderEncoding.cs | 19 +++++++++++++++- .../RequestProcessing/HttpKnownHeaderNames.cs | 19 +++++++++++++++- .../RequestProcessing/HttpReasonPhrase.cs | 17 ++++++++++++++ .../RequestProcessing/HttpStatusCode.cs | 17 ++++++++++++++ .../RequestProcessing/NativeRequestContext.cs | 17 ++++++++++++++ .../RequestProcessing/OpaqueStream.cs | 19 +++++++++++++++- .../RequestProcessing/Request.cs | 17 ++++++++++++++ .../RequestProcessing/RequestContext.cs | 17 ++++++++++++++ .../RequestHeaders.Generated.cs | 19 +++++++++++++++- .../RequestProcessing/RequestHeaders.cs | 17 ++++++++++++++ .../RequestProcessing/RequestStream.cs | 17 ++++++++++++++ .../RequestProcessing/RequestUriBuilder.cs | 21 ++++++++++++++++-- .../RequestProcessing/Response.cs | 17 ++++++++++++++ .../RequestProcessing/ResponseStream.cs | 17 ++++++++++++++ .../ResponseStreamAsyncResult.cs | 19 +++++++++++++++- .../RequestProcessing/SslStatus.cs | 19 +++++++++++++++- .../Resources.Designer.cs | 19 +++++++++++++++- src/Microsoft.Net.Server/TimeoutManager.cs | 19 +++++++++++++++- src/Microsoft.Net.Server/UrlPrefix.cs | 19 +++++++++++++++- src/Microsoft.Net.Server/ValidationHelper.cs | 19 +++++++++++++++- src/Microsoft.Net.Server/WebListener.cs | 17 ++++++++++++++ .../WebListenerException.cs | 17 ++++++++++++++ .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 19 +++++++++++++++- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 19 +++++++++++++++- .../fx/System/Diagnostics/TraceEventType.cs | 19 +++++++++++++++- .../fx/System/ExternDll.cs | 19 +++++++++++++++- .../InteropServices/ExternalException.cs | 19 +++++++++++++++- .../fx/System/SafeNativeMethods.cs | 19 +++++++++++++++- .../ExtendedProtection/ChannelBinding.cs | 19 +++++++++++++++- .../DenyAnonymous.cs | 19 +++++++++++++++- .../DictionaryExtensions.cs | 19 +++++++++++++++- .../DigestTests.cs | 19 +++++++++++++++- .../NegotiateTests.cs | 19 +++++++++++++++- .../PassThroughTests.cs | 19 +++++++++++++++- .../Properties/AssemblyInfo.cs | 17 ++++++++++++++ .../AuthenticationTests.cs | 17 +++++++++++++- .../HttpsTests.cs | 17 +++++++++++++- .../OpaqueUpgradeTests.cs | 17 +++++++++++++- .../Properties/AssemblyInfo.cs | 17 ++++++++++++++ .../RequestBodyTests.cs | 17 +++++++++++++- .../RequestHeaderTests.cs | 17 +++++++++++++- .../RequestTests.cs | 17 +++++++++++++- .../ResponseBodyTests.cs | 17 +++++++++++++- .../ResponseHeaderTests.cs | 17 +++++++++++++- .../ResponseSendFileTests.cs | 17 +++++++++++++- .../ResponseTests.cs | 17 +++++++++++++- .../ServerTests.cs | 17 +++++++++++++- .../Utilities.cs | 17 +++++++++++++- 170 files changed, 2954 insertions(+), 110 deletions(-) diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 6c44c812dd..d411f251a0 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -1,3 +1,19 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Text; diff --git a/samples/SelfHostServer/Properties/AssemblyInfo.cs b/samples/SelfHostServer/Properties/AssemblyInfo.cs index 86b415a1b3..a7dc06e2e0 100644 --- a/samples/SelfHostServer/Properties/AssemblyInfo.cs +++ b/samples/SelfHostServer/Properties/AssemblyInfo.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index b76a42a74f..04097dccec 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -1,4 +1,21 @@ -using Microsoft.AspNet.Abstractions; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Server.WebListener; using Microsoft.Net.Server; diff --git a/samples/TestClient/Program.cs b/samples/TestClient/Program.cs index b1f93759aa..166bb64767 100644 --- a/samples/TestClient/Program.cs +++ b/samples/TestClient/Program.cs @@ -1,4 +1,21 @@ -using System; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; using System.Net; using System.Net.Http; using System.Net.WebSockets; diff --git a/samples/TestClient/Properties/AssemblyInfo.cs b/samples/TestClient/Properties/AssemblyInfo.cs index 6919b6d3ce..249372ae2d 100644 --- a/samples/TestClient/Properties/AssemblyInfo.cs +++ b/samples/TestClient/Properties/AssemblyInfo.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs b/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs index 90a063b5fa..d7f768fe99 100644 --- a/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs +++ b/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs b/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs index ca5902dbd6..e2acc2603b 100644 --- a/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs +++ b/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/Constants.cs b/src/Microsoft.AspNet.Security.Windows/Constants.cs index 28e47e83fc..733190a708 100644 --- a/src/Microsoft.AspNet.Security.Windows/Constants.cs +++ b/src/Microsoft.AspNet.Security.Windows/Constants.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs b/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs index 2d1b86ad04..2a627a5ae6 100644 --- a/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs +++ b/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/DigestCache.cs b/src/Microsoft.AspNet.Security.Windows/DigestCache.cs index 0de3d84475..4b9573c547 100644 --- a/src/Microsoft.AspNet.Security.Windows/DigestCache.cs +++ b/src/Microsoft.AspNet.Security.Windows/DigestCache.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs b/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs index 6064872060..cb0feddc15 100644 --- a/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs +++ b/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs b/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs index 7c41535d5e..331d79a80d 100644 --- a/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs +++ b/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs b/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs index 29ab395d03..be3e58ba26 100644 --- a/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs +++ b/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs b/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs index d60d640f2d..8940131502 100644 --- a/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs +++ b/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs index 8818694ff8..185bf0cb8b 100644 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs index 259dc13382..38acdf476f 100644 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs index 9b9335906f..fc8d821adb 100644 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs index 4d922591dd..a7f83f210c 100644 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs index 81e66a3c30..47dcb0c978 100644 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs index dbbd6d5415..08310bdaf2 100644 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs index 5486b33602..008c713120 100644 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs index ff7a09000b..38628fd240 100644 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs +++ b/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs b/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs index 25cae8a500..32cca3646d 100644 --- a/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs +++ b/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs index dcd73516a9..37f9b57c78 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs index 21ef3b735d..c9595a2f60 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs index 1ac0a7d055..e5613203f9 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs index e7951e2969..5bd541ba73 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs index 52728d3825..5faa836bf6 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs index e30c1ab434..bc7b3da731 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs index 4c04e704b2..5ac2fbc861 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs index 1b720b1ad6..60455aa1da 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs index a0d29a1b61..03428e4c5a 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs index a356f2b3ef..27aaeb05db 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs index 20f85f5010..ddb35763b4 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs index db31e3018a..398d01bffc 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs index 344ef38a59..72972dab9e 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs index 0b42913028..b07be9aff0 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs index 30437854d7..ac65383822 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs index e02c75aaba..d687003b2f 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs index eb48aa1d3f..780678a8f5 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs index 0f1bb3e7a3..1978c950b6 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs index 069223dd4f..d5fe3605ae 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs index 138f12b2bd..ee2d5fc218 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs index df19cf7e37..c25ba8da8d 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs index 2430b73b8d..e96f28dea2 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs index 6be68aa96b..3c17afa5af 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs index 3e8a40d344..2eebb1d6a9 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs b/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs index ab7367c456..68f7b62af3 100644 --- a/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs +++ b/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs b/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs index 37a2caa049..05b2a99940 100644 --- a/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs +++ b/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs b/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs index 40de3afd6d..57adc8e236 100644 --- a/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs +++ b/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs b/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs index 7d2d33ff00..564835a6ba 100644 --- a/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs +++ b/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs b/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs index 85f696728f..9fef272e5b 100644 --- a/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs +++ b/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs b/src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs index 9f503ddd3b..cb5384455b 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs @@ -1,4 +1,21 @@ -using System; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; namespace Microsoft.Net.Runtime { diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 361a26face..efd6fa14f0 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -1,4 +1,21 @@ -using System; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; using System.Collections.Generic; using System.IO; using System.Net; diff --git a/src/Microsoft.AspNet.Server.WebListener/Helpers.cs b/src/Microsoft.AspNet.Server.WebListener/Helpers.cs index ea0ffd4f04..4520aa2adf 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Helpers.cs +++ b/src/Microsoft.AspNet.Server.WebListener/Helpers.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs index d8b5217859..2b73eee9c2 100644 --- a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index dcde3d3e8e..5893617bec 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -1,4 +1,21 @@ -using System; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index f6447300cd..c224e669f6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs index b3e4d9bfca..9f0519042e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -1,4 +1,21 @@ -using System.Reflection; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System.Reflection; using Microsoft.AspNet.Abstractions; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.AspNet.WebSockets/Constants.cs b/src/Microsoft.AspNet.WebSockets/Constants.cs index 6e9cb51ad3..8f4e0df564 100644 --- a/src/Microsoft.AspNet.WebSockets/Constants.cs +++ b/src/Microsoft.AspNet.WebSockets/Constants.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. namespace Microsoft.AspNet.WebSockets { diff --git a/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs b/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs index f4887cc569..3382395c8b 100644 --- a/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs +++ b/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs index 506c830ea2..891c8739f7 100644 --- a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs +++ b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs index d0c02c1842..41a6c1a6a6 100644 --- a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs +++ b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/SR.cs b/src/Microsoft.AspNet.WebSockets/Legacy/SR.cs index a8aeb2a30e..6062f60855 100644 --- a/src/Microsoft.AspNet.WebSockets/Legacy/SR.cs +++ b/src/Microsoft.AspNet.WebSockets/Legacy/SR.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All Rights Reserved. // Information Contained Herein is Proprietary and Confidential. diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs b/src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs index 54abff91bd..f5c77b4eb4 100644 --- a/src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs +++ b/src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs index 43276eefe5..6b0e6e2ee2 100644 --- a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs +++ b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs index 8682c89918..7e404fb597 100644 --- a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs index 60c8341561..fffd04af4f 100644 --- a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs +++ b/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs index 86355cdee4..d9875f0afc 100644 --- a/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs b/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs index a11c34488d..5947567acf 100644 --- a/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs +++ b/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Collections.Generic; diff --git a/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs index 1abade9a33..41718ca34d 100644 --- a/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs b/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs index f23d13af54..b722573934 100644 --- a/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs +++ b/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocket.cs b/src/Microsoft.AspNet.WebSockets/WebSocket.cs index f75e50a3c6..8050263d87 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocket.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocket.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs b/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs index 3e3b798396..66e5aa4760 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs b/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs index 56b24a4fed..2f9522fd40 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs b/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs index a773179e21..313efa3507 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketError.cs b/src/Microsoft.AspNet.WebSockets/WebSocketError.cs index 473bb56349..16ce90e9fd 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketError.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketError.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketException.cs b/src/Microsoft.AspNet.WebSockets/WebSocketException.cs index 64edc3d0cb..b1691a1e1b 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketException.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketException.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs b/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs index abcbd12865..f21108192c 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs @@ -1,4 +1,21 @@ -#if NET45 +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +#if NET45 using Microsoft.AspNet.WebSockets; namespace Owin diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs b/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs index 3479e137fa..331f007ed6 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs b/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs index 1661721a14..2c362f7299 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs b/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs index 7a77a6a4f6..33dfbc97b8 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs @@ -1,4 +1,21 @@ -using System; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs b/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs index a48be62a2d..7513597105 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketState.cs b/src/Microsoft.AspNet.WebSockets/WebSocketState.cs index 3c58d00a20..53d8d2daa5 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketState.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketState.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 861c9e31ab..9e1e783200 100644 --- a/src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,21 @@ -// ==++== +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs b/src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs index c32cafb4e1..f7aa7f941f 100644 --- a/src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs +++ b/src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs @@ -1,4 +1,21 @@ -#if !NET45 +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +#if !NET45 using System; using System.Collections.Generic; diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs index 108303ee2c..ce75afbf7e 100644 --- a/src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs +++ b/src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs index 98303d48b8..cc20e7969c 100644 --- a/src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs +++ b/src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs index 21d82b1de4..eae4f7dae2 100644 --- a/src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs @@ -1,4 +1,21 @@ -// ==++== +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs index 969d273fa8..ae88c8bda9 100644 --- a/src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs b/src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs index 4b6c66b4a4..b6d2d3e3f3 100644 --- a/src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs +++ b/src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs @@ -1,4 +1,21 @@ -#if !NET45 +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +#if !NET45 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Server/AsyncAcceptContext.cs index c21725ff3b..71cc7952e0 100644 --- a/src/Microsoft.Net.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Server/AsyncAcceptContext.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/AuthenticationManager.cs b/src/Microsoft.Net.Server/AuthenticationManager.cs index 396dc6ec4c..ec3452357e 100644 --- a/src/Microsoft.Net.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Server/AuthenticationManager.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/AuthenticationTypes.cs b/src/Microsoft.Net.Server/AuthenticationTypes.cs index 3d27938324..73e07811bd 100644 --- a/src/Microsoft.Net.Server/AuthenticationTypes.cs +++ b/src/Microsoft.Net.Server/AuthenticationTypes.cs @@ -1,4 +1,21 @@ -using System; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Microsoft.Net.Server/Constants.cs b/src/Microsoft.Net.Server/Constants.cs index 0c0ec42840..a85d13c4ae 100644 --- a/src/Microsoft.Net.Server/Constants.cs +++ b/src/Microsoft.Net.Server/Constants.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/DictionaryExtensions.cs b/src/Microsoft.Net.Server/DictionaryExtensions.cs index a1a6e3577a..7aa0e65d2c 100644 --- a/src/Microsoft.Net.Server/DictionaryExtensions.cs +++ b/src/Microsoft.Net.Server/DictionaryExtensions.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/GlobalSuppressions.cs b/src/Microsoft.Net.Server/GlobalSuppressions.cs index 2b0ddbdbf4a6b419d14999f431a6e44ef4126bf5..88c4ba087d0a7235a92981af496c35f0fef54578 100644 GIT binary patch literal 1636 zcmb_cO>?6-5WV|Xba6_iFrLjZGubM}#uM$@-~y7_)YcwkXk+aPi9*6z{{6OO>?DW1 z4F_YS?$@tBUN07~)ZN&N=4j!jx`nN%dTsQn%-E2gK%3uwHs<8)qM2I_H(QCR1;Td})w1T_nGu$|XV7dx!zc`3d576=v zl(sM!Bn)BTAS43*TVZEGD5!MXNx@Zx@G9)l$C*$(!Iud`?=2^DP7d7&`taTmxSdEJ zt?lj?i`UoJhGX~oj-&i?|uVOv(l4#G=<^7e4l8jG z6-cg{fj0<^K4GtfY8<5w`&Jk?6b87eL5fybZvFS$99{eCT;@OLaZq2~Y@7w)rtBg3 zF7=+vV(7Xa&#a=#1b*hY8XtnIM1o(PzkmKuL`&Uwy7#$6;C16886aq{8(+Y$iz^2Y z`E!z+6FWz+yb6efM2f0mKa%QeYMA13G<0e;Nlqv)mP_JWO5U}~L2zq(u^%jw>5*ID zJp%7Yf&@msUZP#E|HjJtgm&lubBQOEVBVDykn~EM;mA)&5(mrs1})H_ILtWqr*wJr`?H>CO(E2UqQ`f-jn)LsU!j-V=b_l*7^NQ5| zj~`+J^=Z@Ea5L>tKGuplH%Lp{u+vmAhZbB)22;&~(9iK1)FA{+!Nth!zBPpouA8dX ze%UFUQX|Ii`1tSFTMRToBhd+q1wpt z{z_sZdh<5S(F%=d6j2YB@!j1opYP+d7j6FHs0Ud;Qp=vX6m?;Ht(w%;pUi(7C@6{B U4>>$QutG`e+ks&n-2OHD4>Vo>=>Px# literal 1926 zcmd6o-HX#u5XI+N@PD}EX$8BhKI*Pe6u)3a=&~TP4{2K4Xw#HUD)gUMe`jvPO`Gof z63EBgxie?ZnYsD*_rfkL*yvGRPwfe)gzM4@t8HUDySLI7wzL-OPu^EHw=2u+BX6}$ zE$2D0ExsFk=hkqQtgLyS6Q#j7c(e+S9Q)4qU*lD>7 z(l6}4w_f#(l_{!3=4LPuY>ZA)c85pY+rnqC3Tw$)yMKm(_SgF!$mtqIN;srN>&#E- zm)89P&!wvrxT}BkR4=W_BQ4~i%<_v!)MvH*Vzt29*XrBB%7_?qS5%5O5AW*SGZJ*CO|!vkS^FM-!-;=oyxYsUa+p2DOeX{DURkqwKeQ|a$7yA_v z6eq`LZqGf&&g1G`s};HlwZ4U~=&_OT+;|;1`IJ%7PjfM3x|?^!PZKjDkJKsbH+JbF zwj$bw_)&LtNm@;4G@TFiSUf+rL~p^UteWE3Zyma9&~Z8i;<*!ZXTGyzxQ{iV$n3M@ zJAHBm`#@H8Pu62J*muxuK{azm)gS7KHGYTsMW#=)tT{aH=#J+&Uu$w`_B4I5yM // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/LogHelper.cs b/src/Microsoft.Net.Server/LogHelper.cs index 611317e3d5..d97a11aea9 100644 --- a/src/Microsoft.Net.Server/LogHelper.cs +++ b/src/Microsoft.Net.Server/LogHelper.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs b/src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs index 5bb16bcb69..1b501e5cad 100644 --- a/src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs +++ b/src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs index ff134adfb4..7d99de7dcf 100644 --- a/src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs b/src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs index 7dac25d72a..6ee9ea9742 100644 --- a/src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs +++ b/src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs index 8538bf8989..b2ffd71a52 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs index ccec530d0b..203785315e 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs b/src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs index 5779ffcbb5..bb8ddc3848 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs b/src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs index a48727e520..b996342215 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs index 1b7fa89c13..549c63ecb0 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs b/src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs index a319d629fd..bf752ab2e2 100644 --- a/src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs +++ b/src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs index c91d2f341d..f0adc64e05 100644 --- a/src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs b/src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs index 3e9d3bb063..1dac268c56 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs index fa057da396..7a24acf6dd 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs index 91e9e953c3..eea727e5fb 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs index cfa8b494fb..eab0a03105 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs index 0a183236b5..daa501bbc1 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs index 4341285b03..fb4f32484b 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs b/src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs index f02fd764fd..8b2acabade 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs b/src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs index f614cbf150..59ea71a2ea 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs b/src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs index 51d3f9474e..0a59d72f45 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs index eccaf869b0..096887987f 100644 --- a/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs index 5713f21df4..04fd65a965 100644 --- a/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs b/src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs index 31357ce6b6..a398747bba 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs index 0600ad3454..f1c4768259 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs b/src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs index 148985426a..4cc96769b7 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs b/src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs index 788477f478..3aaa743291 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs b/src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs index 40836a36ea..5b9596603f 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs b/src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs index 83993f3065..a8535a1951 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs index 15e99f7343..74afb31713 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs index 2016976aa0..6f33ea51d8 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Server/RequestProcessing/Request.cs index 67471d70d5..934c4e7728 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Request.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index 16ac300615..84e3c3ce61 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs index 4ec5271c51..bacf8811a7 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs @@ -1,4 +1,21 @@ -//----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//----------------------------------------------------------------------- // // Copyright (c) Katana Contributors. All rights reserved. // diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs index 43b9fb1e7f..46f432f10b 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs index 312dde4152..40f6e507f3 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs index 4a9bb518de..5127f81281 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. @@ -40,8 +57,8 @@ namespace Microsoft.Net.Server // // When parsing ANSI (Latin 1) encoded path '/pa%C4th/', %C4 will be added to rawOctets and when // we reach 't', the content of rawOctets { 0xC4 } will be fed into the ANSI encoding. The resulting - // string '' will be percent encoded into UTF-8 octets and appended to requestUriString. The final - // path will be '/pa%C3%84th/', where '%C3%84' is the UTF-8 percent encoded character ''. + // string '�' will be percent encoded into UTF-8 octets and appended to requestUriString. The final + // path will be '/pa%C3%84th/', where '%C3%84' is the UTF-8 percent encoded character '�'. private List _rawOctets; private string _rawPath; diff --git a/src/Microsoft.Net.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Server/RequestProcessing/Response.cs index dd9738e443..119cec39a2 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Response.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs index 21b38033e9..5f13a2aaf8 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs index b6d045848c..b771b7b88d 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs b/src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs index cc4debcdaa..056c9e61cb 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/Resources.Designer.cs b/src/Microsoft.Net.Server/Resources.Designer.cs index e0db3bdfbc..b0cf11573e 100644 --- a/src/Microsoft.Net.Server/Resources.Designer.cs +++ b/src/Microsoft.Net.Server/Resources.Designer.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.34006 diff --git a/src/Microsoft.Net.Server/TimeoutManager.cs b/src/Microsoft.Net.Server/TimeoutManager.cs index b90c212758..6789328c1f 100644 --- a/src/Microsoft.Net.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Server/TimeoutManager.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/UrlPrefix.cs b/src/Microsoft.Net.Server/UrlPrefix.cs index 96046033c8..f8b8783813 100644 --- a/src/Microsoft.Net.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Server/UrlPrefix.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/ValidationHelper.cs b/src/Microsoft.Net.Server/ValidationHelper.cs index 5e17218855..ad5ab47d99 100644 --- a/src/Microsoft.Net.Server/ValidationHelper.cs +++ b/src/Microsoft.Net.Server/ValidationHelper.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/WebListener.cs b/src/Microsoft.Net.Server/WebListener.cs index 1d72a75db7..47b987fa41 100644 --- a/src/Microsoft.Net.Server/WebListener.cs +++ b/src/Microsoft.Net.Server/WebListener.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/WebListenerException.cs b/src/Microsoft.Net.Server/WebListenerException.cs index 11a5a2daed..c9d17fca6b 100644 --- a/src/Microsoft.Net.Server/WebListenerException.cs +++ b/src/Microsoft.Net.Server/WebListenerException.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs index 43897343aa..421412244e 100644 --- a/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,21 @@ -// ==++== +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 861c9e31ab..9e1e783200 100644 --- a/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,21 @@ -// ==++== +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Server/fx/System/Diagnostics/TraceEventType.cs index 36d0b93d25..ce9c830d9e 100644 --- a/src/Microsoft.Net.Server/fx/System/Diagnostics/TraceEventType.cs +++ b/src/Microsoft.Net.Server/fx/System/Diagnostics/TraceEventType.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Server/fx/System/ExternDll.cs index 98303d48b8..cc20e7969c 100644 --- a/src/Microsoft.Net.Server/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.Server/fx/System/ExternDll.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Server/fx/System/Runtime/InteropServices/ExternalException.cs index 21d82b1de4..eae4f7dae2 100644 --- a/src/Microsoft.Net.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.Server/fx/System/Runtime/InteropServices/ExternalException.cs @@ -1,4 +1,21 @@ -// ==++== +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Server/fx/System/SafeNativeMethods.cs index 969d273fa8..ae88c8bda9 100644 --- a/src/Microsoft.Net.Server/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.Server/fx/System/SafeNativeMethods.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs b/src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs index 3c31d34a1b..cefd0e12f3 100644 --- a/src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs +++ b/src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs @@ -1,4 +1,21 @@ -//------------------------------------------------------------------------------ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs b/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs index 3bd1cc9f00..19a04912dd 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs +++ b/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs @@ -1,4 +1,21 @@ -// +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// // Copyright 2011-2012 Katana contributors // // diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs b/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs index a1a6e3577a..7aa0e65d2c 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs +++ b/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs index e097a7e65b..67d693ed66 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs +++ b/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs index 572650b9b0..6deff83ee1 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs +++ b/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs index 6ffcf2b8a8..03899b4593 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs +++ b/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs @@ -1,4 +1,21 @@ -// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // diff --git a/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs index 681f7d66cd..c0ff848336 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs +++ b/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 760a21c556..e6acd0f358 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Net; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 73b417ff4a..e9fd2f1aa2 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System.IO; using System.Net.Http; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 45097046fa..3040ddeebc 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. /* TODO: Opaque using System; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs index 9b52afa8d6..ea69d41e45 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs @@ -1,3 +1,20 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + // ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 07ec7bf520..62edea48b6 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.IO; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index b400e8b375..d87dadcc65 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Net.Http; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index fbbc621d3f..93a0f4f041 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.IO; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 0bb29b774f..8f69f36cc7 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Collections.Generic; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 11eff9ff14..d6f5441ce6 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Linq; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 4e0e4b1f27..7e668593c2 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Collections.Generic; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index 55d6a84562..befdfbb97d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Net; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 9c7511aba3..c6f47bb48c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Collections.Generic; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index d96ef5d45d..1a834b99cd 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -1,4 +1,19 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. using System; using System.Threading.Tasks; From da432d05eb6cb8dfcbe68f8365d9da9bfb55a993 Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Fri, 2 May 2014 14:45:29 -0700 Subject: [PATCH 038/597] Updating build scripts --- .gitignore | 1 + build.cmd | 3 +++ build.sh | 30 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 build.sh diff --git a/.gitignore b/.gitignore index 8bc217058d..aba9c594d7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ PublishProfiles/ _ReSharper.* nuget.exe *net45.csproj +*net451.csproj *k10.csproj *.psess *.vsp diff --git a/build.cmd b/build.cmd index 7045ee1f84..2c32132fa3 100644 --- a/build.cmd +++ b/build.cmd @@ -18,6 +18,9 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion +CALL packages\KoreBuild\build\kvm install -svr50 -x86 +CALL packages\KoreBuild\build\kvm install -svrc50 -x86 :run +CALL packages\KoreBuild\build\kvm use default -svr50 -x86 packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh new file mode 100644 index 0000000000..db1e0c3dde --- /dev/null +++ b/build.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +if test `uname` = Darwin; then + cachedir=~/Library/Caches/KBuild +else + if x$XDG_DATA_HOME = x; then + cachedir=$HOME/.local/share + else + cachedir=$XDG_DATA_HOME; + fi +fi +mkdir -p $cachedir + +url=https://www.nuget.org/nuget.exe + +if test ! -f $cachedir/nuget.exe; then + wget -o $cachedir/nuget.exe $url 2>/dev/null || curl -o $cachedir/nuget.exe --location $url /dev/null +fi + +if test ! -e .nuget; then + mkdir .nuget + cp $cachedir/nuget.exe .nuget +fi + +if test ! -d packages/KoreBuild; then + mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + mono .nuget/nuget.exe install Sake -version 0.2 -o packages -ExcludeVersion +fi + +mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" \ No newline at end of file From 5ff7ee9c658c5deef0e3bd48b9f41ca298097009 Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Fri, 2 May 2014 15:07:39 -0700 Subject: [PATCH 039/597] Updating build scripts --- build.cmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cmd b/build.cmd index 2c32132fa3..903d532df3 100644 --- a/build.cmd +++ b/build.cmd @@ -18,8 +18,8 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion -CALL packages\KoreBuild\build\kvm install -svr50 -x86 -CALL packages\KoreBuild\build\kvm install -svrc50 -x86 +CALL packages\KoreBuild\build\kvm upgrade -svr50 -x86 +CALL packages\KoreBuild\build\kvm install default -svrc50 -x86 :run CALL packages\KoreBuild\build\kvm use default -svr50 -x86 From 21616bcde53e4aa64c38151240c073a7c0e3cb16 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 4 May 2014 11:28:12 -0700 Subject: [PATCH 040/597] Fixed up xunit references and fixed sample. --- samples/SelfHostServer/Startup.cs | 1 + test/Microsoft.AspNet.Security.Windows.Test/project.json | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 04097dccec..ed6028e5bc 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -15,6 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. +using Microsoft.AspNet; using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Server.WebListener; using Microsoft.Net.Server; diff --git a/test/Microsoft.AspNet.Security.Windows.Test/project.json b/test/Microsoft.AspNet.Security.Windows.Test/project.json index ecbdca9ad7..f1c9866edb 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/project.json +++ b/test/Microsoft.AspNet.Security.Windows.Test/project.json @@ -2,13 +2,15 @@ "version" : "0.1-alpha-*", "dependencies": { "Microsoft.AspNet.Server.WebListener" : "", - "Microsoft.AspNet.Security.Windows" : "" + "Microsoft.AspNet.Security.Windows" : "", + "xunit.abstractions": "2.0.0-aspnet-*", + "xunit.assert": "2.0.0-aspnet-*", + "xunit.core": "2.0.0-aspnet-*", + "xunit.execution": "2.0.0-aspnet-*" }, "configurations": { "net45": { "dependencies": { - "XUnit": "1.9.2", - "XUnit.Extensions": "1.9.2", "System.Net.Http": "", "System.Net.Http.WebRequest": "" } From 903197e1cee402be92aeb73f06ccf44d0852b796 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 5 May 2014 17:14:45 -0700 Subject: [PATCH 041/597] Fix HttpAbstraction dependencies. --- samples/SelfHostServer/project.json | 2 +- .../FeatureContext.cs | 64 +++++++++---------- .../project.json | 2 +- src/Microsoft.AspNet.WebSockets/project.json | 2 +- .../HttpsTests.cs | 4 +- .../RequestTests.cs | 10 +-- .../ResponseHeaderTests.cs | 14 ++-- .../ResponseSendFileTests.cs | 26 ++++---- .../ResponseTests.cs | 2 +- .../project.json | 2 +- 10 files changed, 64 insertions(+), 64 deletions(-) diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 3bf4abed6e..9502a45614 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,7 @@ { "version" : "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Abstractions": "0.1-alpha-*", + "Microsoft.AspNet.Http": "0.1-alpha-*", "Microsoft.AspNet.Hosting": "0.1-alpha-*", "Microsoft.Net.Server": "", "Microsoft.AspNet.Server.WebListener": "" diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index efd6fa14f0..e217b38495 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -28,7 +28,7 @@ using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener { - internal class FeatureContext : IHttpRequestInformation, IHttpConnection, IHttpResponseInformation, IHttpSendFile, IHttpTransportLayerSecurity, IHttpRequestLifetime + internal class FeatureContext : IHttpRequestFeature, IHttpConnectionFeature, IHttpResponseFeature, IHttpSendFileFeature, IHttpTransportLayerSecurityFeature, IHttpRequestLifetimeFeature { private RequestContext _requestContext; private FeatureCollection _features; @@ -74,16 +74,16 @@ namespace Microsoft.AspNet.Server.WebListener private void PopulateFeatures() { - _features.Add(typeof(IHttpRequestInformation), this); - _features.Add(typeof(IHttpConnection), this); + _features.Add(typeof(IHttpRequestFeature), this); + _features.Add(typeof(IHttpConnectionFeature), this); if (Request.IsSecureConnection) { // TODO: Should this feature be conditional? Should we add this for HTTP requests? - _features.Add(typeof(IHttpTransportLayerSecurity), this); + _features.Add(typeof(IHttpTransportLayerSecurityFeature), this); } - _features.Add(typeof(IHttpResponseInformation), this); - _features.Add(typeof(IHttpSendFile), this); - _features.Add(typeof(IHttpRequestLifetime), this); + _features.Add(typeof(IHttpResponseFeature), this); + _features.Add(typeof(IHttpSendFileFeature), this); + _features.Add(typeof(IHttpRequestLifetimeFeature), this); // TODO: // _environment.CallCancelled = _cts.Token; @@ -98,9 +98,9 @@ namespace Microsoft.AspNet.Server.WebListener */ } - #region IHttpRequestInformation + #region IHttpRequestFeature - Stream IHttpRequestInformation.Body + Stream IHttpRequestFeature.Body { get { @@ -113,7 +113,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _requestBody = value; } } - IDictionary IHttpRequestInformation.Headers + IDictionary IHttpRequestFeature.Headers { get { @@ -126,7 +126,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _requestHeaders = value; } } - string IHttpRequestInformation.Method + string IHttpRequestFeature.Method { get { @@ -139,7 +139,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _httpMethod = value; } } - string IHttpRequestInformation.Path + string IHttpRequestFeature.Path { get { @@ -152,7 +152,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _path = value; } } - string IHttpRequestInformation.PathBase + string IHttpRequestFeature.PathBase { get { @@ -165,7 +165,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _pathBase = value; } } - string IHttpRequestInformation.Protocol + string IHttpRequestFeature.Protocol { get { @@ -190,7 +190,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _httpProtocolVersion = value; } } - string IHttpRequestInformation.QueryString + string IHttpRequestFeature.QueryString { get { @@ -203,7 +203,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _query = value; } } - string IHttpRequestInformation.Scheme + string IHttpRequestFeature.Scheme { get { @@ -216,8 +216,8 @@ namespace Microsoft.AspNet.Server.WebListener set { _scheme = value; } } #endregion - #region IHttpConnection - bool IHttpConnection.IsLocal + #region IHttpConnectionFeature + bool IHttpConnectionFeature.IsLocal { get { @@ -230,7 +230,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _isLocal = value; } } - IPAddress IHttpConnection.LocalIpAddress + IPAddress IHttpConnectionFeature.LocalIpAddress { get { @@ -243,7 +243,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _localIpAddress = value; } } - IPAddress IHttpConnection.RemoteIpAddress + IPAddress IHttpConnectionFeature.RemoteIpAddress { get { @@ -256,7 +256,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _remoteIpAddress = value; } } - int IHttpConnection.LocalPort + int IHttpConnectionFeature.LocalPort { get { @@ -269,7 +269,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _localPort = value; } } - int IHttpConnection.RemotePort + int IHttpConnectionFeature.RemotePort { get { @@ -282,8 +282,8 @@ namespace Microsoft.AspNet.Server.WebListener set { _remotePort = value; } } #endregion - #region IHttpTransportLayerSecurity - X509Certificate IHttpTransportLayerSecurity.ClientCertificate + #region IHttpTransportLayerSecurityFeature + X509Certificate IHttpTransportLayerSecurityFeature.ClientCertificate { get { @@ -296,7 +296,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _clientCert = value; } } - async Task IHttpTransportLayerSecurity.LoadAsync() + async Task IHttpTransportLayerSecurityFeature.LoadAsync() { if (_clientCert == null) { @@ -304,8 +304,8 @@ namespace Microsoft.AspNet.Server.WebListener } } #endregion - #region IHttpResponseInformation - Stream IHttpResponseInformation.Body + #region IHttpResponseFeature + Stream IHttpResponseFeature.Body { get { @@ -318,7 +318,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _responseStream = value; } } - IDictionary IHttpResponseInformation.Headers + IDictionary IHttpResponseFeature.Headers { get { @@ -331,24 +331,24 @@ namespace Microsoft.AspNet.Server.WebListener set { _responseHeaders = value; } } - void IHttpResponseInformation.OnSendingHeaders(Action callback, object state) + void IHttpResponseFeature.OnSendingHeaders(Action callback, object state) { Response.OnSendingHeaders(callback, state); } - string IHttpResponseInformation.ReasonPhrase + string IHttpResponseFeature.ReasonPhrase { get { return Response.ReasonPhrase; } set { Response.ReasonPhrase = value; } } - int IHttpResponseInformation.StatusCode + int IHttpResponseFeature.StatusCode { get { return Response.StatusCode; } set { Response.StatusCode = value; } } #endregion - Task IHttpSendFile.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) + Task IHttpSendFileFeature.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) { return Response.SendFileAsync(path, offset, length, cancellation); } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index ebd2c31782..2e0aa4f30b 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -2,7 +2,7 @@ "version": "0.1-alpha-*", "dependencies": { "Microsoft.Net.Server" : "", - "Microsoft.AspNet.Abstractions": "0.1-alpha-*", + "Microsoft.AspNet.Http": "0.1-alpha-*", "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", "Microsoft.AspNet.FeatureModel": "0.1-alpha-*", diff --git a/src/Microsoft.AspNet.WebSockets/project.json b/src/Microsoft.AspNet.WebSockets/project.json index f7abac917f..fa2484fec2 100644 --- a/src/Microsoft.AspNet.WebSockets/project.json +++ b/src/Microsoft.AspNet.WebSockets/project.json @@ -1,7 +1,7 @@ { "version": "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.Http" : "0.1-alpha-*", "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*" }, "compilationOptions" : { "allowUnsafe": true }, diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index e9fd2f1aa2..1257d82d7b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var tls = httpContext.GetFeature(); + var tls = httpContext.GetFeature(); Assert.NotNull(tls); await tls.LoadAsync(); Assert.Null(tls.ClientCertificate); @@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var tls = httpContext.GetFeature(); + var tls = httpContext.GetFeature(); Assert.NotNull(tls); await tls.LoadAsync(); Assert.NotNull(tls.ClientCertificate); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 93a0f4f041..57bb19b423 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Server.WebListener // General keys // TODO: Assert.True(env.Get("owin.CallCancelled").CanBeCanceled); - var requestInfo = httpContext.GetFeature(); + var requestInfo = httpContext.GetFeature(); // Request Keys Assert.Equal("GET", requestInfo.Method); @@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Server.WebListener // Server Keys // TODO: Assert.NotNull(env.Get>("server.Capabilities")); - var connectionInfo = httpContext.GetFeature(); + var connectionInfo = httpContext.GetFeature(); Assert.Equal("::1", connectionInfo.RemoteIpAddress.ToString()); Assert.NotEqual(0, connectionInfo.RemotePort); Assert.Equal("::1", connectionInfo.LocalIpAddress.ToString()); @@ -96,8 +96,8 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - var requestInfo = httpContext.GetFeature(); - var connectionInfo = httpContext.GetFeature(); + var requestInfo = httpContext.GetFeature(); + var connectionInfo = httpContext.GetFeature(); // Request Keys Assert.Equal("http", requestInfo.Scheme); @@ -137,7 +137,7 @@ namespace Microsoft.AspNet.Server.WebListener using (CreateServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var requestInfo = httpContext.GetFeature(); + var requestInfo = httpContext.GetFeature(); try { Assert.Equal(expectedPath, requestInfo.Path); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index d6f5441ce6..726455a650 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders["WWW-Authenticate"] = new string[] { "custom1" }; return Task.FromResult(0); @@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders["WWW-Authenticate"] = new string[] { "custom1, and custom2", "custom3" }; return Task.FromResult(0); @@ -104,7 +104,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders["Custom-Header1"] = new string[] { "custom1, and custom2", "custom3" }; return Task.FromResult(0); @@ -128,7 +128,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders["Connection"] = new string[] { "Close" }; return Task.FromResult(0); @@ -205,7 +205,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders["Transfer-Encoding"] = new string[] { "chunked" }; return responseInfo.Body.WriteAsync(new byte[10], 0, 10); @@ -233,7 +233,7 @@ namespace Microsoft.AspNet.Server.WebListener env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); @@ -263,7 +263,7 @@ namespace Microsoft.AspNet.Server.WebListener async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 7e668593c2..eda1f7c2de 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -65,7 +65,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal("Overlapped", support.Get("sendfile.Concurrency")); */ - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); Assert.NotNull(sendFile); } catch (Exception ex) @@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); try { sendFile.SendFileAsync(string.Empty, 0, null, CancellationToken.None).Wait(); @@ -126,7 +126,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { @@ -145,7 +145,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); })) { @@ -164,7 +164,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); httpContext.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) @@ -184,7 +184,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); httpContext.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None).Wait(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); @@ -205,7 +205,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); })) { @@ -224,7 +224,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); })) { @@ -239,7 +239,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); })) { @@ -254,7 +254,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) { @@ -273,7 +273,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); httpContext.Response.Headers["Content-lenGth"] = FileLength.ToString(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) @@ -294,7 +294,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); httpContext.Response.Headers["Content-lenGth"] = "10"; return sendFile.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); })) @@ -315,7 +315,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.GetFeature(); httpContext.Response.Headers["Content-lenGth"] = "0"; return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index befdfbb97d..7e411dba05 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 201; - httpContext.GetFeature().ReasonPhrase = "CustomReasonPhrase"; // TODO? + httpContext.GetFeature().ReasonPhrase = "CustomReasonPhrase"; // TODO? // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value return Task.FromResult(0); })) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 4f6ab2edbd..6ff4fe92b9 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -11,7 +11,7 @@ "xunit.execution": "2.0.0-aspnet-*", "Microsoft.AspNet.Server.WebListener" : "", "Microsoft.Net.Server" : "", - "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.Http" : "0.1-alpha-*", "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", From 1952e683acd0f9aec4205bc22ad74f11ab099e8b Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 5 May 2014 18:24:59 -0700 Subject: [PATCH 042/597] Fix a few more HttpAbstractions references. --- samples/SelfHostServer/Startup.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index ed6028e5bc..c34e761ca7 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -16,7 +16,7 @@ // permissions and limitations under the License. using Microsoft.AspNet; -using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Server.WebListener; using Microsoft.Net.Server; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index c224e669f6..22a328883a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -38,7 +38,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.Http; using Microsoft.AspNet.ConfigurationModel; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Logging; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs index 9f0519042e..3576acae05 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -16,7 +16,7 @@ // permissions and limitations under the License. using System.Reflection; -using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.Http; namespace Microsoft.AspNet.Server.WebListener { From bc93ff9aec368cecd17d570a9d267dbcecb6f444 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Mon, 5 May 2014 20:08:02 -0700 Subject: [PATCH 043/597] Update dependency namespace --- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- .../project.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 22a328883a..84ccb37d30 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -39,7 +39,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.AspNet.Http; -using Microsoft.AspNet.ConfigurationModel; +using Microsoft.Framework.ConfigurationModel; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Logging; using Microsoft.Net.Server; diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 2e0aa4f30b..d81533884c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -3,7 +3,7 @@ "dependencies": { "Microsoft.Net.Server" : "", "Microsoft.AspNet.Http": "0.1-alpha-*", - "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", + "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", "Microsoft.AspNet.FeatureModel": "0.1-alpha-*", "Microsoft.AspNet.Logging": "0.1-alpha-*", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 6ff4fe92b9..743f55652b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -12,7 +12,7 @@ "Microsoft.AspNet.Server.WebListener" : "", "Microsoft.Net.Server" : "", "Microsoft.AspNet.Http" : "0.1-alpha-*", - "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", + "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*", From 3c38eb1f358ae8f4725df9d441e56f58413ad313 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Tue, 6 May 2014 00:35:11 -0700 Subject: [PATCH 044/597] React to renames --- samples/SelfHostServer/Startup.cs | 1 + src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 1 + src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index c34e761ca7..e37f198434 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -16,6 +16,7 @@ // permissions and limitations under the License. using Microsoft.AspNet; +using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Server.WebListener; using Microsoft.Net.Server; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 84ccb37d30..9b2f4d9697 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -40,6 +40,7 @@ using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.Framework.ConfigurationModel; +using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Logging; using Microsoft.Net.Server; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs index 3576acae05..ef9e0bdda1 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -16,6 +16,7 @@ // permissions and limitations under the License. using System.Reflection; +using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; namespace Microsoft.AspNet.Server.WebListener From 13e595ee1840c781364392e546ed68d5375cbdfb Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 6 May 2014 12:09:02 -0700 Subject: [PATCH 045/597] Fix Logging dependency. --- src/Microsoft.AspNet.Server.WebListener/LogHelper.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/MessagePump.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Server/LogHelper.cs | 2 +- src/Microsoft.Net.Server/Project.json | 2 +- src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs | 2 +- src/Microsoft.Net.Server/WebListener.cs | 2 +- .../project.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs index 2b73eee9c2..28559308b6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -24,7 +24,7 @@ using System; using System.Diagnostics; using System.Globalization; -using Microsoft.AspNet.Logging; +using Microsoft.Framework.Logging; namespace Microsoft.AspNet.Server.WebListener { diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index 5893617bec..bcf7ba653f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -19,7 +19,7 @@ using System; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Logging; +using Microsoft.Framework.Logging; using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 9b2f4d9697..dc991bac57 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -42,7 +42,7 @@ using Microsoft.AspNet.Http; using Microsoft.Framework.ConfigurationModel; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Logging; +using Microsoft.Framework.Logging; using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index d81533884c..f7726aaf2e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -6,7 +6,7 @@ "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", "Microsoft.AspNet.FeatureModel": "0.1-alpha-*", - "Microsoft.AspNet.Logging": "0.1-alpha-*", + "Microsoft.Framework.Logging": "0.1-alpha-*", "Microsoft.AspNet.Hosting": "0.1-alpha-*" }, "compilationOptions": { diff --git a/src/Microsoft.Net.Server/LogHelper.cs b/src/Microsoft.Net.Server/LogHelper.cs index d97a11aea9..5b7efd1830 100644 --- a/src/Microsoft.Net.Server/LogHelper.cs +++ b/src/Microsoft.Net.Server/LogHelper.cs @@ -24,7 +24,7 @@ using System; using System.Diagnostics; using System.Globalization; -using Microsoft.AspNet.Logging; +using Microsoft.Framework.Logging; namespace Microsoft.Net.Server { diff --git a/src/Microsoft.Net.Server/Project.json b/src/Microsoft.Net.Server/Project.json index d948282b13..ed01ca0d23 100644 --- a/src/Microsoft.Net.Server/Project.json +++ b/src/Microsoft.Net.Server/Project.json @@ -1,7 +1,7 @@ { "version": "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Logging": "0.1-alpha-*" + "Microsoft.Framework.Logging": "0.1-alpha-*" }, "compilationOptions": { "allowUnsafe": true diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index 84e3c3ce61..ca09228b6d 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Logging; +using Microsoft.Framework.Logging; namespace Microsoft.Net.Server { diff --git a/src/Microsoft.Net.Server/WebListener.cs b/src/Microsoft.Net.Server/WebListener.cs index 47b987fa41..6fc5ce742e 100644 --- a/src/Microsoft.Net.Server/WebListener.cs +++ b/src/Microsoft.Net.Server/WebListener.cs @@ -32,7 +32,7 @@ using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Logging; +using Microsoft.Framework.Logging; namespace Microsoft.Net.Server { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 743f55652b..ae4b58fe2c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -16,7 +16,7 @@ "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*", - "Microsoft.AspNet.Logging": "0.1-alpha-*", + "Microsoft.Framework.Logging": "0.1-alpha-*", "Microsoft.AspNet.Hosting": "0.1-alpha-*" }, "configurations": { From 81abb2d4315116c2051649d7a764c5f9f603563d Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 6 May 2014 14:25:07 -0700 Subject: [PATCH 046/597] Fix ordering of usings and dependencies after namespace renaming --- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 4 ++-- src/Microsoft.AspNet.Server.WebListener/project.json | 6 +++--- .../project.json | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index dc991bac57..a5a80ecce4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -38,10 +38,10 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -using Microsoft.AspNet.Http; -using Microsoft.Framework.ConfigurationModel; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Hosting.Server; +using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.Logging; using Microsoft.Net.Server; diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index f7726aaf2e..bc18c897d1 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -3,11 +3,11 @@ "dependencies": { "Microsoft.Net.Server" : "", "Microsoft.AspNet.Http": "0.1-alpha-*", - "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", "Microsoft.AspNet.FeatureModel": "0.1-alpha-*", - "Microsoft.Framework.Logging": "0.1-alpha-*", - "Microsoft.AspNet.Hosting": "0.1-alpha-*" + "Microsoft.AspNet.Hosting": "0.1-alpha-*", + "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", + "Microsoft.Framework.Logging": "0.1-alpha-*" }, "compilationOptions": { "allowUnsafe": true diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index ae4b58fe2c..ede15ba43b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -12,12 +12,12 @@ "Microsoft.AspNet.Server.WebListener" : "", "Microsoft.Net.Server" : "", "Microsoft.AspNet.Http" : "0.1-alpha-*", - "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*", - "Microsoft.Framework.Logging": "0.1-alpha-*", - "Microsoft.AspNet.Hosting": "0.1-alpha-*" + "Microsoft.AspNet.Hosting": "0.1-alpha-*", + "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", + "Microsoft.Framework.Logging": "0.1-alpha-*" }, "configurations": { "net45": { From 98f14182b190d9dfff78f5332a4792b34ee9cfc5 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 6 May 2014 12:17:35 -0700 Subject: [PATCH 047/597] Remove AssemblyInfo files. Remove direct OWIN references. --- .../SelfHostServer/Properties/AssemblyInfo.cs | 59 ------------------ samples/SelfHostServer/SelfHostServer.kproj | 1 - .../project.json | 1 - .../Microsoft.AspNet.WebSockets.kproj | 1 - .../Properties/AssemblyInfo.cs | 53 ---------------- .../WebSocketExtensions.cs | 5 +- .../WebSocketMiddleware.cs | 3 +- src/Microsoft.AspNet.WebSockets/project.json | 2 - .../Microsoft.Net.Server.kproj | 1 - .../Properties/AssemblyInfo.cs | 61 ------------------- src/Microsoft.Net.Server/WebListener.cs | 2 +- .../Properties/AssemblyInfo.cs | 43 ------------- 12 files changed, 6 insertions(+), 226 deletions(-) delete mode 100644 samples/SelfHostServer/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.Net.Server/Properties/AssemblyInfo.cs diff --git a/samples/SelfHostServer/Properties/AssemblyInfo.cs b/samples/SelfHostServer/Properties/AssemblyInfo.cs deleted file mode 100644 index a7dc06e2e0..0000000000 --- a/samples/SelfHostServer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SelfHostServer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SelfHostServer")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("ec50ddb4-9ec6-4cbd-96ac-15de948247cc")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.5")] -[assembly: AssemblyVersion("0.5")] -[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index 199bbb5a01..2da6845307 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -22,7 +22,6 @@ - diff --git a/src/Microsoft.AspNet.Security.Windows/project.json b/src/Microsoft.AspNet.Security.Windows/project.json index 3fe6a340df..599c58c415 100644 --- a/src/Microsoft.AspNet.Security.Windows/project.json +++ b/src/Microsoft.AspNet.Security.Windows/project.json @@ -7,7 +7,6 @@ { "net45" : { "dependencies": { - "Owin": "1.0" } } } diff --git a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj b/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj index 94229fc81d..f584e250bb 100644 --- a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj +++ b/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj @@ -40,7 +40,6 @@ - diff --git a/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs deleted file mode 100644 index 41718ca34d..0000000000 --- a/src/Microsoft.AspNet.WebSockets/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Microsoft.AspNet.WebSockets")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.AspNet.WebSockets")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("1f471909-581f-4060-a147-430891e9c3c1")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.5")] -[assembly: AssemblyVersion("0.5")] -[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs b/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs index f21108192c..ccacef2231 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs @@ -14,7 +14,7 @@ // NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing // permissions and limitations under the License. - +/* #if NET45 using Microsoft.AspNet.WebSockets; @@ -28,4 +28,5 @@ namespace Owin } } } -#endif \ No newline at end of file +#endif +*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs b/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs index 33dfbc97b8..8ed52f1ba7 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs +++ b/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs @@ -14,7 +14,7 @@ // NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing // permissions and limitations under the License. - +/* using System; using System.Collections.Generic; using System.IO; @@ -182,3 +182,4 @@ namespace Microsoft.AspNet.WebSockets } } } +*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/project.json b/src/Microsoft.AspNet.WebSockets/project.json index fa2484fec2..da531b3e9e 100644 --- a/src/Microsoft.AspNet.WebSockets/project.json +++ b/src/Microsoft.AspNet.WebSockets/project.json @@ -8,8 +8,6 @@ "configurations": { "net45" : { "dependencies": { - "Owin": "1.0", - "Microsoft.Owin": "2.1.0" } } } diff --git a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj index 1599915ded..93c2bc3c87 100644 --- a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj +++ b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj @@ -54,7 +54,6 @@ - diff --git a/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs deleted file mode 100644 index 04fd65a965..0000000000 --- a/src/Microsoft.Net.Server/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Microsoft.Net.Server")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.Net.Server")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("1f471909-581f-4060-a147-430891e9c3c1")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.5")] -[assembly: AssemblyVersion("0.5")] -[assembly: AssemblyFileVersion("0.5.40117.0")] -[assembly: CLSCompliant(true)] diff --git a/src/Microsoft.Net.Server/WebListener.cs b/src/Microsoft.Net.Server/WebListener.cs index 6fc5ce742e..ba54332fde 100644 --- a/src/Microsoft.Net.Server/WebListener.cs +++ b/src/Microsoft.Net.Server/WebListener.cs @@ -39,7 +39,7 @@ namespace Microsoft.Net.Server using AppFunc = Func; /// - /// An HTTP server wrapping the Http.Sys APIs that accepts requests and passes them on to the given OWIN application. + /// An HTTP server wrapping the Http.Sys APIs that accepts requests. /// public sealed class WebListener : IDisposable { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs index ea69d41e45..a462d9475f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs @@ -15,48 +15,5 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Microsoft.AspNet.Server.WebListener.FunctionalTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.AspNet.Server.WebListener.FunctionalTests")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("a265fcd6-3542-4f59-a1dd-ad423d40ddde")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.5")] -[assembly: AssemblyVersion("0.5")] -[assembly: AssemblyFileVersion("0.5.40117.0")] - // These tests can't run in parallel because they all use the same port. [assembly: Xunit.CollectionBehaviorAttribute(Xunit.CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] From 9c5253a415b079975512367157f35b1f94fb61f4 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 7 May 2014 18:28:44 -0700 Subject: [PATCH 048/597] Sort dependencies and remove duplicates in dependencies --- samples/SelfHostServer/project.json | 8 +++---- .../project.json | 14 +++++------ src/Microsoft.Net.Server/Project.json | 6 ++--- .../project.json | 2 +- .../project.json | 24 +++++++++---------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 9502a45614..9945c5dac2 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,10 +1,10 @@ { "version" : "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Http": "0.1-alpha-*", "Microsoft.AspNet.Hosting": "0.1-alpha-*", - "Microsoft.Net.Server": "", - "Microsoft.AspNet.Server.WebListener": "" + "Microsoft.AspNet.Http": "0.1-alpha-*", + "Microsoft.AspNet.Server.WebListener": "", + "Microsoft.Net.Server": "" }, "commands": { "web": "Microsoft.AspNet.Hosting server.name=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001" }, "configurations": { @@ -12,8 +12,8 @@ }, "k10": { "dependencies": { - "System.Console": "4.0.0.0", "System.Collections": "4.0.0.0", + "System.Console": "4.0.0.0", "System.Diagnostics.Debug": "4.0.10.0", "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index bc18c897d1..459e0d16de 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,13 +1,13 @@ { "version": "0.1-alpha-*", "dependencies": { - "Microsoft.Net.Server" : "", - "Microsoft.AspNet.Http": "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", "Microsoft.AspNet.FeatureModel": "0.1-alpha-*", "Microsoft.AspNet.Hosting": "0.1-alpha-*", + "Microsoft.AspNet.Http": "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", - "Microsoft.Framework.Logging": "0.1-alpha-*" + "Microsoft.Framework.Logging": "0.1-alpha-*", + "Microsoft.Net.Server" : "" }, "compilationOptions": { "allowUnsafe": true @@ -16,6 +16,7 @@ "net45": {}, "k10": { "dependencies": { + "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.0.0", "System.Collections.Concurrent": "4.0.0.0", "System.Diagnostics.Contracts": "4.0.0.0", @@ -28,16 +29,15 @@ "System.Resources.ResourceManager": "4.0.0.0", "System.Runtime": "4.0.20.0", "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.InteropServices": "4.0.20.0", "System.Runtime.Handles": "4.0.0.0", + "System.Runtime.InteropServices": "4.0.20.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", "System.Text.Encoding.Extensions": "4.0.10.0", "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", "System.Threading.Tasks": "4.0.10.0", - "System.Threading.ThreadPool": "4.0.10.0", - "Microsoft.Win32.Primitives": "4.0.0.0" + "System.Threading.ThreadPool": "4.0.10.0" } } } diff --git a/src/Microsoft.Net.Server/Project.json b/src/Microsoft.Net.Server/Project.json index ed01ca0d23..a6363b7940 100644 --- a/src/Microsoft.Net.Server/Project.json +++ b/src/Microsoft.Net.Server/Project.json @@ -10,6 +10,7 @@ "net45": {}, "k10": { "dependencies": { + "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.0.0", "System.Collections.Concurrent": "4.0.0.0", "System.Diagnostics.Contracts": "4.0.0.0", @@ -25,8 +26,8 @@ "System.Resources.ResourceManager": "4.0.0.0", "System.Runtime": "4.0.20.0", "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.InteropServices": "4.0.20.0", "System.Runtime.Handles": "4.0.0.0", + "System.Runtime.InteropServices": "4.0.20.0", "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", @@ -34,8 +35,7 @@ "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", "System.Threading.Tasks": "4.0.10.0", - "System.Threading.ThreadPool": "4.0.10.0", - "Microsoft.Win32.Primitives": "4.0.0.0" + "System.Threading.ThreadPool": "4.0.10.0" } } } diff --git a/test/Microsoft.AspNet.Security.Windows.Test/project.json b/test/Microsoft.AspNet.Security.Windows.Test/project.json index f1c9866edb..90274d6696 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/project.json +++ b/test/Microsoft.AspNet.Security.Windows.Test/project.json @@ -1,8 +1,8 @@ { "version" : "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Server.WebListener" : "", "Microsoft.AspNet.Security.Windows" : "", + "Microsoft.AspNet.Server.WebListener" : "", "xunit.abstractions": "2.0.0-aspnet-*", "xunit.assert": "2.0.0-aspnet-*", "xunit.core": "2.0.0-aspnet-*", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index ede15ba43b..57deecbd1e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -4,27 +4,27 @@ "test": "Xunit.KRunner" }, "dependencies": { - "Xunit.KRunner": "0.1-alpha-*", + "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", + "Microsoft.AspNet.Hosting": "0.1-alpha-*", + "Microsoft.AspNet.Http" : "0.1-alpha-*", + "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", + "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*", + "Microsoft.AspNet.Server.WebListener" : "", + "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", + "Microsoft.Framework.Logging": "0.1-alpha-*", + "Microsoft.Net.Server" : "", "xunit.abstractions": "2.0.0-aspnet-*", "xunit.assert": "2.0.0-aspnet-*", "xunit.core": "2.0.0-aspnet-*", "xunit.execution": "2.0.0-aspnet-*", - "Microsoft.AspNet.Server.WebListener" : "", - "Microsoft.Net.Server" : "", - "Microsoft.AspNet.Http" : "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", - "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", - "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*", - "Microsoft.AspNet.Hosting": "0.1-alpha-*", - "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", - "Microsoft.Framework.Logging": "0.1-alpha-*" + "Xunit.KRunner": "0.1-alpha-*" }, "configurations": { "net45": { "dependencies": { - "System.Runtime": "", "System.Net.Http": "", - "System.Net.Http.WebRequest": "" + "System.Net.Http.WebRequest": "", + "System.Runtime": "" } } } From 72e14ebd6fa62758940b759ebb7ae2c862470431 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 1 May 2014 17:28:32 -0700 Subject: [PATCH 049/597] Copy the tests for the lower level API. --- WebListener.sln | 13 + .../Resources.Designer.cs | 2 +- .../ResponseBodyTests.cs | 4 +- .../AuthenticationTests.cs | 119 +++++++ .../HttpsTests.cs | 170 +++++++++ ...Microsoft.Net.Server.FunctionalTests.kproj | 39 +++ .../OpaqueUpgradeTests.cs | 322 ++++++++++++++++++ .../Project.json | 24 ++ .../Properties/AssemblyInfo.cs | 8 + .../RequestBodyTests.cs | 249 ++++++++++++++ .../RequestHeaderTests.cs | 100 ++++++ .../RequestTests.cs | 130 +++++++ .../ResponseBodyTests.cs | 192 +++++++++++ .../ResponseHeaderTests.cs | 286 ++++++++++++++++ .../ResponseSendFileTests.cs | 274 +++++++++++++++ .../ResponseTests.cs | 131 +++++++ .../ServerTests.cs | 210 ++++++++++++ .../Utilities.cs | 38 +++ 18 files changed, 2308 insertions(+), 3 deletions(-) create mode 100644 test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj create mode 100644 test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/Project.json create mode 100644 test/Microsoft.Net.Server.FunctionalTests/Properties/AssemblyInfo.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/Utilities.cs diff --git a/WebListener.sln b/WebListener.sln index e2a7a67d0b..c3c21e8fe7 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -25,6 +25,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.Web EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.kproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Server.FunctionalTests", "test\Microsoft.Net.Server.FunctionalTests\Microsoft.Net.Server.FunctionalTests.kproj", "{DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -115,6 +117,16 @@ Global {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.Build.0 = Release|x86 {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|x86.ActiveCfg = Release|x86 {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|x86.Build.0 = Release|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Any CPU.ActiveCfg = Debug|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|x86.ActiveCfg = Debug|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|x86.Build.0 = Debug|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Any CPU.ActiveCfg = Release|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.Build.0 = Release|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|x86.ActiveCfg = Release|x86 + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -128,5 +140,6 @@ Global {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {4492FF4C-9032-411D-853F-46B01755E504} = {E183C826-1360-4DFF-9994-F33CED5C8525} {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1} = {E183C826-1360-4DFF-9994-F33CED5C8525} EndGlobalSection EndGlobal diff --git a/src/Microsoft.Net.Server/Resources.Designer.cs b/src/Microsoft.Net.Server/Resources.Designer.cs index b0cf11573e..9fdfa80837 100644 --- a/src/Microsoft.Net.Server/Resources.Designer.cs +++ b/src/Microsoft.Net.Server/Resources.Designer.cs @@ -56,7 +56,7 @@ namespace Microsoft.Net.Server { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNet.Server.WebListener.Resources", System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Resources)).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Net.Server.Resources", System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Resources)).Assembly); resourceMan = temp; } return resourceMan; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 8f69f36cc7..3aa245dddb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -120,7 +120,7 @@ namespace Microsoft.AspNet.Server.WebListener } */ [Fact] - public void ResponseBody_WriteContentLengthNoneWritten_Throws() + public async Task ResponseBody_WriteContentLengthNoneWritten_Throws() { using (Utilities.CreateHttpServer(env => { @@ -129,7 +129,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - Assert.Throws(() => SendRequestAsync(Address).Result); + await Assert.ThrowsAsync(() => SendRequestAsync(Address)); } } diff --git a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs new file mode 100644 index 0000000000..593575806c --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class AuthenticationTests + { + private const string Address = "http://localhost:8080/"; + + [Theory] + [InlineData(AuthenticationType.Kerberos)] + [InlineData(AuthenticationType.Negotiate)] + [InlineData(AuthenticationType.Ntlm)] + [InlineData(AuthenticationType.Digest)] + [InlineData(AuthenticationType.Basic)] + [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | AuthenticationType.Digest | AuthenticationType.Basic)] + public async Task AuthTypes_EnabledButNotChalleneged_PassThrough(AuthenticationType authType) + { + using (var server = Utilities.CreateAuthServer(authType)) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Dispose(); + + var response = await responseTask; + response.EnsureSuccessStatusCode(); + } + } + + [Theory] + [InlineData(AuthenticationType.Kerberos)] + [InlineData(AuthenticationType.Negotiate)] + [InlineData(AuthenticationType.Ntlm)] + // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented + [InlineData(AuthenticationType.Basic)] + public async Task AuthType_Specify401_ChallengesAdded(AuthenticationType authType) + { + using (var server = Utilities.CreateAuthServer(authType)) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = 401; + context.Dispose(); + + var response = await responseTask; + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + } + } + + [Fact] + public async Task MultipleAuthTypes_Specify401_ChallengesAdded() + { + using (var server = Utilities.CreateAuthServer( + AuthenticationType.Kerberos + | AuthenticationType.Negotiate + | AuthenticationType.Ntlm + /* | AuthenticationType.Digest TODO: Not implemented */ + | AuthenticationType.Basic)) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = 401; + context.Dispose(); + + var response = await responseTask; + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal("Kerberos, Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + } + } + /* TODO: User + [Theory] + [InlineData(AuthenticationType.Kerberos)] + [InlineData(AuthenticationType.Negotiate)] + [InlineData(AuthenticationType.Ntlm)] + // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationType.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | / *AuthenticationType.Digest |* / AuthenticationType.Basic)] + public async Task AuthTypes_Login_Success(AuthenticationType authType) + { + int requestCount = 0; + using (Utilities.CreateAuthServer(authType, env => + { + requestCount++; + / * // TODO: Expose user as feature. + object obj; + if (env.TryGetValue("server.User", out obj) && obj != null) + { + return Task.FromResult(0); + }* / + new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address, useDefaultCredentials: true); + response.EnsureSuccessStatusCode(); + } + } + */ + + private async Task SendRequestAsync(string uri, bool useDefaultCredentials = false) + { + HttpClientHandler handler = new HttpClientHandler(); + handler.UseDefaultCredentials = useDefaultCredentials; + using (HttpClient client = new HttpClient(handler)) + { + return await client.GetAsync(uri); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs new file mode 100644 index 0000000000..e4c13293eb --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System.IO; +using System.Net.Http; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class HttpsTests + { + private const string Address = "https://localhost:9090/"; + + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + public async Task Https_200OK_Success() + { + using (var server = Utilities.CreateHttpsServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + public async Task Https_SendHelloWorld_Success() + { + using (var server = Utilities.CreateHttpsServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + byte[] body = Encoding.UTF8.GetBytes("Hello World"); + context.Response.ContentLength = body.Length; + await context.Response.Body.WriteAsync(body, 0, body.Length); + context.Dispose(); + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + public async Task Https_EchoHelloWorld_Success() + { + using (var server = Utilities.CreateHttpsServer()) + { + Task responseTask = SendRequestAsync(Address, "Hello World"); + + var context = await server.GetContextAsync(); + string input = new StreamReader(context.Request.Body).ReadToEnd(); + Assert.Equal("Hello World", input); + context.Response.ContentLength = 11; + using (var writer = new StreamWriter(context.Response.Body)) + { + writer.Write("Hello World"); + } + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + public async Task Https_ClientCertNotSent_ClientCertNotPresent() + { + using (var server = Utilities.CreateHttpsServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + var cert = await context.Request.GetClientCertificateAsync(); + Assert.Null(cert); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + public async Task Https_ClientCertRequested_ClientCertPresent() + { + using (var server = Utilities.CreateHttpsServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + var cert = await context.Request.GetClientCertificateAsync(); + Assert.NotNull(cert); + context.Dispose(); + + X509Certificate2 clientCert = FindClientCert(); + Assert.NotNull(clientCert); + string response = await SendRequestAsync(Address, clientCert); + Assert.Equal(string.Empty, response); + } + } + + private async Task SendRequestAsync(string uri, + X509Certificate cert = null) + { + WebRequestHandler handler = new WebRequestHandler(); + handler.ServerCertificateValidationCallback = (a, b, c, d) => true; + if (cert != null) + { + handler.ClientCertificates.Add(cert); + } + using (HttpClient client = new HttpClient(handler)) + { + return await client.GetStringAsync(uri); + } + } + + private async Task SendRequestAsync(string uri, string upload) + { + WebRequestHandler handler = new WebRequestHandler(); + handler.ServerCertificateValidationCallback = (a, b, c, d) => true; + using (HttpClient client = new HttpClient(handler)) + { + HttpResponseMessage response = await client.PostAsync(uri, new StringContent(upload)); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + } + + private X509Certificate2 FindClientCert() + { + var store = new X509Store(); + store.Open(OpenFlags.ReadOnly); + + foreach (var cert in store.Certificates) + { + bool isClientAuth = false; + bool isSmartCard = false; + foreach (var extension in cert.Extensions) + { + var eku = extension as X509EnhancedKeyUsageExtension; + if (eku != null) + { + foreach (var oid in eku.EnhancedKeyUsages) + { + if (oid.FriendlyName == "Client Authentication") + { + isClientAuth = true; + } + else if (oid.FriendlyName == "Smart Card Logon") + { + isSmartCard = true; + break; + } + } + } + } + + if (isClientAuth && !isSmartCard) + { + return cert; + } + } + return null; + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj new file mode 100644 index 0000000000..93b8944285 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj @@ -0,0 +1,39 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + dcb6e0b1-223d-44e6-8696-4767e5b6e6a1 + Library + net45 + + + + + + + 2.0 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs new file mode 100644 index 0000000000..031aeeca3b --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -0,0 +1,322 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +/* TODO: Opaque +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; +using Xunit.Extensions; + +namespace Microsoft.Net.Server +{ + using AppFunc = Func; + using OpaqueUpgrade = Action, Func, Task>>; + + public class OpaqueUpgradeTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task OpaqueUpgrade_SupportKeys_Present() + { + using (CreateServer(env => + { + try + { + IDictionary capabilities = env.Get>("server.Capabilities"); + Assert.NotNull(capabilities); + + Assert.Equal("1.0", capabilities.Get("opaque.Version")); + + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + Assert.NotNull(opaqueUpgrade); + } + catch (Exception ex) + { + byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(0, response.Content.Headers.ContentLength); + Assert.Equal(string.Empty, response.Content.ReadAsStringAsync().Result); + } + } + + [Fact] + public async Task OpaqueUpgrade_NullCallback_Throws() + { + using (CreateServer(env => + { + try + { + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + opaqueUpgrade(new Dictionary(), null); + } + catch (Exception ex) + { + byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Contains("callback", response.Content.ReadAsStringAsync().Result); + } + } + + [Fact] + public async Task OpaqueUpgrade_AfterHeadersSent_Throws() + { + bool? upgradeThrew = null; + using (CreateServer(env => + { + byte[] body = Encoding.UTF8.GetBytes("Hello World"); + env.Get("owin.ResponseBody").Write(body, 0, body.Length); + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + try + { + opaqueUpgrade(null, _ => Task.FromResult(0)); + upgradeThrew = false; + } + catch (InvalidOperationException) + { + upgradeThrew = true; + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.True(upgradeThrew.Value); + } + } + + [Fact] + public async Task OpaqueUpgrade_GetUpgrade_Success() + { + ManualResetEvent waitHandle = new ManualResetEvent(false); + bool? callbackInvoked = null; + using (CreateServer(env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Upgrade"] = new string[] { "websocket" }; // Win8.1 blocks anything but WebSockets + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + opaqueUpgrade(null, opqEnv => + { + callbackInvoked = true; + waitHandle.Set(); + return Task.FromResult(0); + }); + return Task.FromResult(0); + })) + { + using (Stream stream = await SendOpaqueRequestAsync("GET", Address)) + { + Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); + Assert.True(callbackInvoked.HasValue, "CallbackInvoked not set"); + Assert.True(callbackInvoked.Value, "Callback not invoked"); + } + } + } + + [Theory] + // See HTTP_VERB for known verbs + [InlineData("UNKNOWN", null)] + [InlineData("INVALID", null)] + [InlineData("OPTIONS", null)] + [InlineData("GET", null)] + [InlineData("HEAD", null)] + [InlineData("DELETE", null)] + [InlineData("TRACE", null)] + [InlineData("CONNECT", null)] + [InlineData("TRACK", null)] + [InlineData("MOVE", null)] + [InlineData("COPY", null)] + [InlineData("PROPFIND", null)] + [InlineData("PROPPATCH", null)] + [InlineData("MKCOL", null)] + [InlineData("LOCK", null)] + [InlineData("UNLOCK", null)] + [InlineData("SEARCH", null)] + [InlineData("CUSTOMVERB", null)] + [InlineData("PATCH", null)] + [InlineData("POST", "Content-Length: 0")] + [InlineData("PUT", "Content-Length: 0")] + public async Task OpaqueUpgrade_VariousMethodsUpgradeSendAndReceive_Success(string method, string extraHeader) + { + using (CreateServer(env => + { + var responseHeaders = env.Get>("owin.ResponseHeaders"); + responseHeaders["Upgrade"] = new string[] { "WebSocket" }; // Win8.1 blocks anything but WebSockets + OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + opaqueUpgrade(null, async opqEnv => + { + Stream opaqueStream = opqEnv.Get("opaque.Stream"); + + byte[] buffer = new byte[100]; + int read = await opaqueStream.ReadAsync(buffer, 0, buffer.Length); + + await opaqueStream.WriteAsync(buffer, 0, read); + }); + return Task.FromResult(0); + })) + { + using (Stream stream = await SendOpaqueRequestAsync(method, Address, extraHeader)) + { + byte[] data = new byte[100]; + stream.WriteAsync(data, 0, 49).Wait(); + int read = stream.ReadAsync(data, 0, data.Length).Result; + Assert.Equal(49, read); + } + } + } + + [Theory] + // Http.Sys returns a 411 Length Required if PUT or POST does not specify content-length or chunked. + [InlineData("POST", "Content-Length: 10")] + [InlineData("POST", "Transfer-Encoding: chunked")] + [InlineData("PUT", "Content-Length: 10")] + [InlineData("PUT", "Transfer-Encoding: chunked")] + [InlineData("CUSTOMVERB", "Content-Length: 10")] + [InlineData("CUSTOMVERB", "Transfer-Encoding: chunked")] + public void OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) + { + OpaqueUpgrade opaqueUpgrade = null; + using (CreateServer(env => + { + opaqueUpgrade = env.Get("opaque.Upgrade"); + if (opaqueUpgrade == null) + { + throw new NotImplementedException(); + } + opaqueUpgrade(null, opqEnv => Task.FromResult(0)); + return Task.FromResult(0); + })) + { + Assert.Throws(() => + { + try + { + return SendOpaqueRequestAsync(method, Address, extraHeader).Result; + } + catch (AggregateException ag) + { + throw ag.GetBaseException(); + } + }); + Assert.Null(opaqueUpgrade); + } + } + + private IDisposable CreateServer(AppFunc app) + { + IDictionary properties = new Dictionary(); + IList> addresses = new List>(); + properties["host.Addresses"] = addresses; + + IDictionary address = new Dictionary(); + addresses.Add(address); + + address["scheme"] = "http"; + address["host"] = "localhost"; + address["port"] = "8080"; + address["path"] = string.Empty; + + OwinServerFactory.Initialize(properties); + + return OwinServerFactory.Create(app, properties); + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + + // Returns a bidirectional opaque stream or throws if the upgrade fails + private async Task SendOpaqueRequestAsync(string method, string address, string extraHeader = null) + { + // Connect with a socket + Uri uri = new Uri(address); + TcpClient client = new TcpClient(); + try + { + await client.ConnectAsync(uri.Host, uri.Port); + NetworkStream stream = client.GetStream(); + + // Send an HTTP GET request + byte[] requestBytes = BuildGetRequest(method, uri, extraHeader); + await stream.WriteAsync(requestBytes, 0, requestBytes.Length); + + // Read the response headers, fail if it's not a 101 + await ParseResponseAsync(stream); + + // Return the opaque network stream + return stream; + } + catch (Exception) + { + client.Close(); + throw; + } + } + + private byte[] BuildGetRequest(string method, Uri uri, string extraHeader) + { + StringBuilder builder = new StringBuilder(); + builder.Append(method); + builder.Append(" "); + builder.Append(uri.PathAndQuery); + builder.Append(" HTTP/1.1"); + builder.AppendLine(); + + builder.Append("Host: "); + builder.Append(uri.Host); + builder.Append(':'); + builder.Append(uri.Port); + builder.AppendLine(); + + if (!string.IsNullOrEmpty(extraHeader)) + { + builder.AppendLine(extraHeader); + } + + builder.AppendLine(); + return Encoding.ASCII.GetBytes(builder.ToString()); + } + + // Read the response headers, fail if it's not a 101 + private async Task ParseResponseAsync(NetworkStream stream) + { + StreamReader reader = new StreamReader(stream); + string statusLine = await reader.ReadLineAsync(); + string[] parts = statusLine.Split(' '); + if (int.Parse(parts[1]) != 101) + { + throw new InvalidOperationException("The response status code was incorrect: " + statusLine); + } + + // Scan to the end of the headers + while (!string.IsNullOrEmpty(reader.ReadLine())) + { + } + } + } +} +*/ \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/Project.json b/test/Microsoft.Net.Server.FunctionalTests/Project.json new file mode 100644 index 0000000000..286adb463e --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/Project.json @@ -0,0 +1,24 @@ +{ + "version" : "0.1-alpha-*", + "commands": { + "test": "Xunit.KRunner" + }, + "dependencies": { + "Xunit.KRunner": "0.1-alpha-*", + "xunit.abstractions": "2.0.0-aspnet-*", + "xunit.assert": "2.0.0-aspnet-*", + "xunit.core": "2.0.0-aspnet-*", + "xunit.execution": "2.0.0-aspnet-*", + "Microsoft.Net.Server" : "", + "Microsoft.AspNet.Logging": "0.1-alpha-*" + }, + "configurations": { + "net45": { + "dependencies": { + "System.Runtime": "", + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" + } + } + } +} diff --git a/test/Microsoft.Net.Server.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.Net.Server.FunctionalTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..1bc3b800fb --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +// These tests can't run in parallel because they all use the same port. +[assembly: Xunit.CollectionBehaviorAttribute(Xunit.CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs new file mode 100644 index 0000000000..89f6d14d32 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs @@ -0,0 +1,249 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class RequestBodyTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task RequestBody_ReadSync_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address, "Hello World"); + + var context = await server.GetContextAsync(); + byte[] input = new byte[100]; + int read = context.Request.Body.Read(input, 0, input.Length); + context.Response.ContentLength = read; + context.Response.Body.Write(input, 0, read); + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task RequestBody_ReadAync_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address, "Hello World"); + + var context = await server.GetContextAsync(); + byte[] input = new byte[100]; + int read = await context.Request.Body.ReadAsync(input, 0, input.Length); + context.Response.ContentLength = read; + await context.Response.Body.WriteAsync(input, 0, read); + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } +#if NET45 + [Fact] + public async Task RequestBody_ReadBeginEnd_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address, "Hello World"); + + var context = await server.GetContextAsync(); + byte[] input = new byte[100]; + int read = context.Request.Body.EndRead(context.Request.Body.BeginRead(input, 0, input.Length, null, null)); + context.Response.ContentLength = read; + context.Response.Body.EndWrite(context.Response.Body.BeginWrite(input, 0, read, null, null)); + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } +#endif + + [Fact] + public async Task RequestBody_InvalidBuffer_ArgumentException() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address, "Hello World"); + + var context = await server.GetContextAsync(); + byte[] input = new byte[100]; + Assert.Throws("buffer", () => context.Request.Body.Read(null, 0, 1)); + Assert.Throws("offset", () => context.Request.Body.Read(input, -1, 1)); + Assert.Throws("offset", () => context.Request.Body.Read(input, input.Length + 1, 1)); + Assert.Throws("size", () => context.Request.Body.Read(input, 10, -1)); + Assert.Throws("size", () => context.Request.Body.Read(input, 0, 0)); + Assert.Throws("size", () => context.Request.Body.Read(input, 1, input.Length)); + Assert.Throws("size", () => context.Request.Body.Read(input, 0, input.Length + 1)); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestBody_ReadSyncPartialBody_Success() + { + StaggardContent content = new StaggardContent(); + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address, content); + + var context = await server.GetContextAsync(); + byte[] input = new byte[10]; + int read = context.Request.Body.Read(input, 0, input.Length); + Assert.Equal(5, read); + content.Block.Release(); + read = context.Request.Body.Read(input, 0, input.Length); + Assert.Equal(5, read); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestBody_ReadAsyncPartialBody_Success() + { + StaggardContent content = new StaggardContent(); + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address, content); + + var context = await server.GetContextAsync(); + byte[] input = new byte[10]; + int read = await context.Request.Body.ReadAsync(input, 0, input.Length); + Assert.Equal(5, read); + content.Block.Release(); + read = await context.Request.Body.ReadAsync(input, 0, input.Length); + Assert.Equal(5, read); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestBody_PostWithImidateBody_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendSocketRequestAsync(Address); + + var context = await server.GetContextAsync(); + byte[] input = new byte[11]; + int read = await context.Request.Body.ReadAsync(input, 0, input.Length); + Assert.Equal(10, read); + read = await context.Request.Body.ReadAsync(input, 0, input.Length); + Assert.Equal(0, read); + context.Response.ContentLength = 10; + await context.Response.Body.WriteAsync(input, 0, 10); + context.Dispose(); + + string response = await responseTask; + string[] lines = response.Split('\r', '\n'); + Assert.Equal(13, lines.Length); + Assert.Equal("HTTP/1.1 200 OK", lines[0]); + Assert.Equal("0123456789", lines[12]); + } + } + + private Task SendRequestAsync(string uri, string upload) + { + return SendRequestAsync(uri, new StringContent(upload)); + } + + private async Task SendRequestAsync(string uri, HttpContent content) + { + using (HttpClient client = new HttpClient()) + { + HttpResponseMessage response = await client.PostAsync(uri, content); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + } + + private async Task SendSocketRequestAsync(string address) + { + // Connect with a socket + Uri uri = new Uri(address); + TcpClient client = new TcpClient(); + try + { + await client.ConnectAsync(uri.Host, uri.Port); + NetworkStream stream = client.GetStream(); + + // Send an HTTP GET request + byte[] requestBytes = BuildPostRequest(uri); + await stream.WriteAsync(requestBytes, 0, requestBytes.Length); + StreamReader reader = new StreamReader(stream); + return await reader.ReadToEndAsync(); + } + catch (Exception) + { + client.Close(); + throw; + } + } + + private byte[] BuildPostRequest(Uri uri) + { + StringBuilder builder = new StringBuilder(); + builder.Append("POST"); + builder.Append(" "); + builder.Append(uri.PathAndQuery); + builder.Append(" HTTP/1.1"); + builder.AppendLine(); + + builder.Append("Host: "); + builder.Append(uri.Host); + builder.Append(':'); + builder.Append(uri.Port); + builder.AppendLine(); + + builder.AppendLine("Connection: close"); + builder.AppendLine("Content-Length: 10"); + builder.AppendLine(); + builder.Append("0123456789"); + return Encoding.ASCII.GetBytes(builder.ToString()); + } + + private class StaggardContent : HttpContent + { + public StaggardContent() + { + Block = new SemaphoreSlim(0, 1); + } + + public SemaphoreSlim Block { get; private set; } + + protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) + { + await stream.WriteAsync(new byte[5], 0, 5); + await Block.WaitAsync(); + await stream.WriteAsync(new byte[5], 0, 5); + } + + protected override bool TryComputeLength(out long length) + { + length = 10; + return true; + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs new file mode 100644 index 0000000000..7a4122db53 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System.Linq; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class RequestHeaderTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task RequestHeaders_ClientSendsDefaultHeaders_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + var requestHeaders = context.Request.Headers; + // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. + // Assert.Equal(2, requestHeaders.Count); + // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); + Assert.Equal("localhost:8080", requestHeaders["Host"].First()); + string[] values; + Assert.False(requestHeaders.TryGetValue("Accept", out values)); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestHeaders_ClientSendsCustomHeaders_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + string[] customValues = new string[] { "custom1, and custom2", "custom3" }; + Task responseTask = SendRequestAsync("localhost", 8080, "Custom-Header", customValues); + + var context = await server.GetContextAsync(); + var requestHeaders = context.Request.Headers; + Assert.Equal(4, requestHeaders.Count); + Assert.Equal("localhost:8080", requestHeaders["Host"].First()); + Assert.Equal("close", requestHeaders["Connection"].First()); + Assert.Equal(1, requestHeaders["Custom-Header"].Length); + // Apparently Http.Sys squashes request headers together. + Assert.Equal("custom1, and custom2, custom3", requestHeaders["Custom-Header"].First()); + Assert.Equal(1, requestHeaders["Spacer-Header"].Length); + Assert.Equal("spacervalue, spacervalue", requestHeaders["Spacer-Header"].First()); + context.Dispose(); + + await responseTask; + } + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetStringAsync(uri); + } + } + + private async Task SendRequestAsync(string host, int port, string customHeader, string[] customValues) + { + StringBuilder builder = new StringBuilder(); + builder.AppendLine("GET / HTTP/1.1"); + builder.AppendLine("Connection: close"); + builder.Append("HOST: "); + builder.Append(host); + builder.Append(':'); + builder.AppendLine(port.ToString()); + foreach (string value in customValues) + { + builder.Append(customHeader); + builder.Append(": "); + builder.AppendLine(value); + builder.AppendLine("Spacer-Header: spacervalue"); + } + builder.AppendLine(); + + byte[] request = Encoding.ASCII.GetBytes(builder.ToString()); + + Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + socket.Connect(host, port); + + socket.Send(request); + + byte[] response = new byte[1024 * 5]; + await Task.Run(() => socket.Receive(response)); + socket.Close(); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs new file mode 100644 index 0000000000..54ef27e237 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs @@ -0,0 +1,130 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class RequestTests + { + private const string Address = "http://localhost:8080"; + + [Fact] + public async Task Request_SimpleGet_Success() + { + using (var server = Utilities.CreateServer("http", "localhost", "8080", "/basepath")) + { + Task responseTask = SendRequestAsync(Address + "/basepath/SomePath?SomeQuery"); + + var context = await server.GetContextAsync(); + + // General fields + var request = context.Request; + + // Request Keys + Assert.Equal("GET", request.Method); + Assert.Equal(Stream.Null, request.Body); + Assert.NotNull(request.Headers); + Assert.Equal("http", request.Scheme); + Assert.Equal("/basepath", request.PathBase); + Assert.Equal("/SomePath", request.Path); + Assert.Equal("?SomeQuery", request.QueryString); + Assert.Equal(new Version(1, 1), request.ProtocolVersion); + + Assert.Equal("::1", request.RemoteIpAddress.ToString()); + Assert.NotEqual(0, request.RemotePort); + Assert.Equal("::1", request.LocalIpAddress.ToString()); + Assert.NotEqual(0, request.LocalPort); + Assert.True(request.IsLocal); + + // Note: Response keys are validated in the ResponseTests + + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Theory] + [InlineData("/", "http://localhost:8080/", "", "/")] + [InlineData("/basepath/", "http://localhost:8080/basepath", "/basepath", "")] + [InlineData("/basepath/", "http://localhost:8080/basepath/", "/basepath", "/")] + [InlineData("/basepath/", "http://localhost:8080/basepath/subpath", "/basepath", "/subpath")] + [InlineData("/base path/", "http://localhost:8080/base%20path/sub path", "/base path", "/sub path")] + [InlineData("/base葉path/", "http://localhost:8080/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] + public async Task Request_PathSplitting(string pathBase, string requestUri, string expectedPathBase, string expectedPath) + { + using (var server = Utilities.CreateServer("http", "localhost", "8080", pathBase)) + { + Task responseTask = SendRequestAsync(requestUri); + + var context = await server.GetContextAsync(); + + // General fields + var request = context.Request; + + // Request Keys + Assert.Equal("http", request.Scheme); + Assert.Equal(expectedPath, request.Path); + Assert.Equal(expectedPathBase, request.PathBase); + Assert.Equal(string.Empty, request.QueryString); + Assert.Equal(8080, request.LocalPort); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Theory] + // The test server defines these prefixes: "/", "/11", "/2/3", "/2", "/11/2" + [InlineData("/", "", "/")] + [InlineData("/random", "", "/random")] + [InlineData("/11", "/11", "")] + [InlineData("/11/", "/11", "/")] + [InlineData("/11/random", "/11", "/random")] + [InlineData("/2", "/2", "")] + [InlineData("/2/", "/2", "/")] + [InlineData("/2/random", "/2", "/random")] + [InlineData("/2/3", "/2/3", "")] + [InlineData("/2/3/", "/2/3", "/")] + [InlineData("/2/3/random", "/2/3", "/random")] + public async Task Request_MultiplePrefixes(string requestUri, string expectedPathBase, string expectedPath) + { + using (var server = new WebListener()) + { + foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) + { + server.UrlPrefixes.Add(UrlPrefix.Create("http", "localhost", "8080", path)); + } + server.Start(); + + Task responseTask = SendRequestAsync(Address + requestUri); + + var context = await server.GetContextAsync(); + var request = context.Request; + + Assert.Equal(expectedPath, request.Path); + Assert.Equal(expectedPathBase, request.PathBase); + + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetStringAsync(uri); + } + } + } +} diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs new file mode 100644 index 0000000000..25a125372f --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class ResponseBodyTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Body.Write(new byte[10], 0, 10); + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_WriteChunked_Chunked() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Request.Headers["transfeR-Encoding"] = new[] { " CHunked " }; + Stream stream = context.Response.Body; + stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); + stream.Write(new byte[10], 0, 10); + await stream.WriteAsync(new byte[10], 0, 10); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_WriteContentLength_PassedThrough() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = new[] { " 30 " }; + Stream stream = context.Response.Body; + stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); + stream.Write(new byte[10], 0, 10); + await stream.WriteAsync(new byte[10], 0, 10); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal("30", contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); + } + } + /* TODO: response protocol + [Fact] + public async Task ResponseBody_Http10WriteNoHeaders_DefaultsConnectionClose() + { + using (Utilities.CreateHttpServer(env => + { + env["owin.ResponseProtocol"] = "HTTP/1.0"; + env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); + return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); // Http.Sys won't transmit 1.0 + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + */ + /* TODO: Why does this test time out? + [Fact] + public async Task ResponseBody_WriteContentLengthNoneWritten_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = new[] { " 20 " }; + context.Dispose(); + + await Assert.ThrowsAsync(() => responseTask); + } + } + */ + [Fact] + public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = new[] { " 20 " }; + context.Response.Body.Write(new byte[5], 0, 5); + context.Dispose(); + + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = new[] { " 10 " }; + context.Response.Body.Write(new byte[5], 0, 5); + Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); + context.Dispose(); + + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task ResponseBody_WriteContentLengthExtraWritten_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = new[] { " 10 " }; + context.Response.Body.Write(new byte[10], 0, 10); + Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal("10", contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + } + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs new file mode 100644 index 0000000000..4411ba1d74 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs @@ -0,0 +1,286 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class ResponseHeaderTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task ResponseHeaders_ServerSendsDefaultHeaders_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(2, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.Equal(1, response.Content.Headers.Count()); + Assert.Equal(0, response.Content.Headers.ContentLength); + } + } + + [Fact] + public async Task ResponseHeaders_ServerSendsSingleValueKnownHeaders_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + WebRequest request = WebRequest.Create(Address); + Task responseTask = request.GetResponseAsync(); + + var context = await server.GetContextAsync(); + var responseHeaders = context.Response.Headers; + responseHeaders["WWW-Authenticate"] = new string[] { "custom1" }; + context.Dispose(); + + // HttpClient would merge the headers no matter what + HttpWebResponse response = (HttpWebResponse)await responseTask; + Assert.Equal(4, response.Headers.Count); + Assert.Null(response.Headers["Transfer-Encoding"]); + Assert.Equal(0, response.ContentLength); + Assert.NotNull(response.Headers["Date"]); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); + Assert.Equal(new string[] { "custom1" }, response.Headers.GetValues("WWW-Authenticate")); + } + } + + [Fact] + public async Task ResponseHeaders_ServerSendsMultiValueKnownHeaders_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + WebRequest request = WebRequest.Create(Address); + Task responseTask = request.GetResponseAsync(); + + var context = await server.GetContextAsync(); + var responseHeaders = context.Response.Headers; + responseHeaders["WWW-Authenticate"] = new string[] { "custom1, and custom2", "custom3" }; + context.Dispose(); + + // HttpClient would merge the headers no matter what + HttpWebResponse response = (HttpWebResponse)await responseTask; + Assert.Equal(4, response.Headers.Count); + Assert.Null(response.Headers["Transfer-Encoding"]); + Assert.Equal(0, response.ContentLength); + Assert.NotNull(response.Headers["Date"]); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); + Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); + } + } + + [Fact] + public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + WebRequest request = WebRequest.Create(Address); + Task responseTask = request.GetResponseAsync(); + + var context = await server.GetContextAsync(); + var responseHeaders = context.Response.Headers; + responseHeaders["Custom-Header1"] = new string[] { "custom1, and custom2", "custom3" }; + context.Dispose(); + + // HttpClient would merge the headers no matter what + HttpWebResponse response = (HttpWebResponse)await responseTask; + Assert.Equal(4, response.Headers.Count); + Assert.Null(response.Headers["Transfer-Encoding"]); + Assert.Equal(0, response.ContentLength); + Assert.NotNull(response.Headers["Date"]); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); + Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); + } + } + + [Fact] + public async Task ResponseHeaders_ServerSendsConnectionClose_Closed() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + var responseHeaders = context.Response.Headers; + responseHeaders["Connection"] = new string[] { "Close" }; + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + /* TODO: + [Fact] + public async Task ResponseHeaders_SendsHttp10_Gets11Close() + { + using (Utilities.CreateHttpServer(env => + { + env["owin.ResponseProtocol"] = "HTTP/1.0"; + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + + [Fact] + public async Task ResponseHeaders_SendsHttp10WithBody_Gets11Close() + { + using (Utilities.CreateHttpServer(env => + { + env["owin.ResponseProtocol"] = "HTTP/1.0"; + return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.False(response.Content.Headers.Contains("Content-Length")); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + */ + + [Fact] + public async Task ResponseHeaders_HTTP10Request_Gets11Close() + { + using (var server = Utilities.CreateHttpServer()) + { + using (HttpClient client = new HttpClient()) + { + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Address); + request.Version = new Version(1, 0); + Task responseTask = client.SendAsync(request); + + var context = await server.GetContextAsync(); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + } + + [Fact] + public async Task ResponseHeaders_HTTP10Request_RemovesChunkedHeader() + { + using (var server = Utilities.CreateHttpServer()) + { + using (HttpClient client = new HttpClient()) + { + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Address); + request.Version = new Version(1, 0); + Task responseTask = client.SendAsync(request); + + var context = await server.GetContextAsync(); + var responseHeaders = context.Response.Headers; + responseHeaders["Transfer-Encoding"] = new string[] { "chunked" }; + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.False(response.Content.Headers.Contains("Content-Length")); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + } + } + } + + [Fact] + public async Task Headers_FlushSendsHeaders_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + var responseHeaders = context.Response.Headers; + + responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); + responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); + var body = context.Response.Body; + body.Flush(); + Assert.Throws(() => context.Response.StatusCode = 404); + responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored + + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(5, response.Headers.Count()); // Date, Server, Chunked + + Assert.Equal(2, response.Headers.GetValues("Custom1").Count()); + Assert.Equal("value1a", response.Headers.GetValues("Custom1").First()); + Assert.Equal("value1b", response.Headers.GetValues("Custom1").Skip(1).First()); + Assert.Equal(1, response.Headers.GetValues("Custom2").Count()); + Assert.Equal("value2a, value2b", response.Headers.GetValues("Custom2").First()); + } + } + + [Fact] + public async Task Headers_FlushAsyncSendsHeaders_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + var responseHeaders = context.Response.Headers; + + responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); + responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); + var body = context.Response.Body; + await body.FlushAsync(); + Assert.Throws(() => context.Response.StatusCode = 404); + responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored + + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(5, response.Headers.Count()); // Date, Server, Chunked + + Assert.Equal(2, response.Headers.GetValues("Custom1").Count()); + Assert.Equal("value1a", response.Headers.GetValues("Custom1").First()); + Assert.Equal("value1b", response.Headers.GetValues("Custom1").Skip(1).First()); + Assert.Equal(1, response.Headers.GetValues("Custom2").Count()); + Assert.Equal("value2a, value2b", response.Headers.GetValues("Custom2").First()); + } + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs new file mode 100644 index 0000000000..ff9fb85c9c --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs @@ -0,0 +1,274 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class ResponseSendFileTests + { + private const string Address = "http://localhost:8080/"; + private readonly string AbsoluteFilePath; + private readonly string RelativeFilePath; + private readonly long FileLength; + + public ResponseSendFileTests() + { + AbsoluteFilePath = Directory.GetFiles(Environment.CurrentDirectory).First(); + RelativeFilePath = Path.GetFileName(AbsoluteFilePath); + FileLength = new FileInfo(AbsoluteFilePath).Length; + } + + [Fact] + public async Task ResponseSendFile_MissingFile_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + await Assert.ThrowsAsync(() => + context.Response.SendFileAsync("Missing.txt", 0, null, CancellationToken.None)); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + } + } + + [Fact] + public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(FileLength, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_RelativeFile_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + await context.Response.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(FileLength, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_Chunked_Chunked() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Transfer-EncodinG"] = new[] { "CHUNKED" }; + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(FileLength, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_MultipleChunks_Chunked() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Transfer-EncodinG"] = new[] { "CHUNKED" }; + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_ChunkedHalfOfFile_Chunked() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + await context.Response.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(FileLength / 2, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_ChunkedOffsetOutOfRange_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + await Assert.ThrowsAsync( + () => context.Response.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None)); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + } + } + + [Fact] + public async Task ResponseSendFile_ChunkedCountOutOfRange_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + await Assert.ThrowsAsync( + () => context.Response.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None)); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + } + } + + [Fact] + public async Task ResponseSendFile_ChunkedCount0_Chunked() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_ContentLength_PassedThrough() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = new[] { FileLength.ToString() }; + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal(FileLength.ToString(), contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(FileLength, response.Content.ReadAsByteArrayAsync().Result.Length); + } + } + + [Fact] + public async Task ResponseSendFile_ContentLengthSpecific_PassedThrough() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = new[] { "10" }; + await context.Response.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal("10", contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(10, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_ContentLength0_PassedThrough() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = new[] { "0" }; + await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.Equal("0", contentLength.First()); + Assert.Null(response.Headers.TransferEncodingChunked); + Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs new file mode 100644 index 0000000000..6aaceeff89 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class ResponseTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task Response_ServerSendsDefaultResponse_ServerProvidesStatusCodeAndReasonPhrase() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + Assert.Equal(200, context.Response.StatusCode); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("OK", response.ReasonPhrase); + Assert.Equal(new Version(1, 1), response.Version); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task Response_ServerSendsSpecificStatus_ServerProvidesReasonPhrase() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = 201; + // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(201, (int)response.StatusCode); + Assert.Equal("Created", response.ReasonPhrase); + Assert.Equal(new Version(1, 1), response.Version); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task Response_ServerSendsSpecificStatusAndReasonPhrase_PassedThrough() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = 201; + context.Response.ReasonPhrase = "CustomReasonPhrase"; + // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(201, (int)response.StatusCode); + Assert.Equal("CustomReasonPhrase", response.ReasonPhrase); + Assert.Equal(new Version(1, 1), response.Version); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task Response_ServerSendsCustomStatus_NoReasonPhrase() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = 901; + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(901, (int)response.StatusCode); + Assert.Equal(string.Empty, response.ReasonPhrase); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task Response_100_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + Assert.Throws(() => { context.Response.StatusCode = 100; }); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + } + } + + [Fact] + public async Task Response_0_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + Assert.Throws(() => { context.Response.StatusCode = 0; }); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + } + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs new file mode 100644 index 0000000000..5778917050 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs @@ -0,0 +1,210 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class ServerTests + { + private const string Address = "http://localhost:8080/"; + + [Fact] + public async Task Server_200OK_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task Server_SendHelloWorld_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Response.ContentLength = 11; + using (var writer = new StreamWriter(context.Response.Body)) + { + writer.Write("Hello World"); + } + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task Server_EchoHelloWorld_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task responseTask = SendRequestAsync(Address, "Hello World"); + + var context = await server.GetContextAsync(); + string input = new StreamReader(context.Request.Body).ReadToEnd(); + Assert.Equal("Hello World", input); + context.Response.ContentLength = 11; + using (var writer = new StreamWriter(context.Response.Body)) + { + writer.Write("Hello World"); + } + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + + [Fact] + public async Task Server_ClientDisconnects_CallCancelled() + { + TimeSpan interval = TimeSpan.FromSeconds(1); + ManualResetEvent canceled = new ManualResetEvent(false); + + using (var server = Utilities.CreateHttpServer()) + { + // Note: System.Net.Sockets does not RST the connection by default, it just FINs. + // Http.Sys's disconnect notice requires a RST. + Task responseTask = SendHungRequestAsync("GET", Address); + + var context = await server.GetContextAsync(); + CancellationToken ct = context.DisconnectToken; + Assert.True(ct.CanBeCanceled, "CanBeCanceled"); + Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); + ct.Register(() => canceled.Set()); + + using (Socket socket = await responseTask) + { + socket.Close(0); // Force a RST + } + Assert.True(canceled.WaitOne(interval), "canceled"); + Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); + + context.Dispose(); + } + } + + [Fact] + public async Task Server_Abort_CallCancelled() + { + TimeSpan interval = TimeSpan.FromSeconds(1); + ManualResetEvent canceled = new ManualResetEvent(false); + + using (var server = Utilities.CreateHttpServer()) + { + // Note: System.Net.Sockets does not RST the connection by default, it just FINs. + // Http.Sys's disconnect notice requires a RST. + Task responseTask = SendHungRequestAsync("GET", Address); + + var context = await server.GetContextAsync(); + CancellationToken ct = context.DisconnectToken; + Assert.True(ct.CanBeCanceled, "CanBeCanceled"); + Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); + ct.Register(() => canceled.Set()); + context.Abort(); + Assert.True(canceled.WaitOne(interval), "Aborted"); + Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); + + using (Socket socket = await responseTask) + { + Assert.Throws(() => socket.Receive(new byte[10])); + } + } + } + + [Fact] + public async Task Server_SetQueueLimit_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + server.SetRequestQueueLimit(1001); + Task responseTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + private async Task SendRequestAsync(string uri) + { + ServicePointManager.DefaultConnectionLimit = 100; + using (HttpClient client = new HttpClient()) + { + return await client.GetStringAsync(uri); + } + } + + private async Task SendRequestAsync(string uri, string upload) + { + using (HttpClient client = new HttpClient()) + { + HttpResponseMessage response = await client.PostAsync(uri, new StringContent(upload)); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + } + + private async Task SendHungRequestAsync(string method, string address) + { + // Connect with a socket + Uri uri = new Uri(address); + TcpClient client = new TcpClient(); + try + { + await client.ConnectAsync(uri.Host, uri.Port); + NetworkStream stream = client.GetStream(); + + // Send an HTTP GET request + byte[] requestBytes = BuildGetRequest(method, uri); + await stream.WriteAsync(requestBytes, 0, requestBytes.Length); + + // Return the opaque network stream + return client.Client; + } + catch (Exception) + { + client.Close(); + throw; + } + } + + private byte[] BuildGetRequest(string method, Uri uri) + { + StringBuilder builder = new StringBuilder(); + builder.Append(method); + builder.Append(" "); + builder.Append(uri.PathAndQuery); + builder.Append(" HTTP/1.1"); + builder.AppendLine(); + + builder.Append("Host: "); + builder.Append(uri.Host); + builder.Append(':'); + builder.Append(uri.Port); + builder.AppendLine(); + + builder.AppendLine(); + return Encoding.ASCII.GetBytes(builder.ToString()); + } + } +} diff --git a/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs new file mode 100644 index 0000000000..c11b7596f1 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.Net.Server +{ + internal static class Utilities + { + internal static WebListener CreateHttpServer() + { + return CreateServer("http", "localhost", "8080", string.Empty); + } + + internal static WebListener CreateHttpsServer() + { + return CreateServer("https", "localhost", "9090", string.Empty); + } + + internal static WebListener CreateAuthServer(AuthenticationType authType) + { + return CreateServer("http", "localhost", "8080", string.Empty, authType); + } + + internal static WebListener CreateServer(string scheme, string host, string port, string path) + { + return CreateServer(scheme, host, port, path, AuthenticationType.None); + } + + internal static WebListener CreateServer(string scheme, string host, string port, string path, AuthenticationType authType) + { + WebListener listener = new WebListener(); + listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); + listener.AuthenticationManager.AuthenticationTypes = authType; + listener.Start(); + return listener; + } + } +} From 3c5a5346c60eb3ad7e6ed48d9a06a28c67fa87ab Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 8 May 2014 12:10:55 -0700 Subject: [PATCH 050/597] Sort dependencies. --- test/Microsoft.Net.Server.FunctionalTests/Project.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.Net.Server.FunctionalTests/Project.json b/test/Microsoft.Net.Server.FunctionalTests/Project.json index 286adb463e..410147cdf0 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Project.json +++ b/test/Microsoft.Net.Server.FunctionalTests/Project.json @@ -4,20 +4,20 @@ "test": "Xunit.KRunner" }, "dependencies": { + "Microsoft.AspNet.Logging": "0.1-alpha-*", + "Microsoft.Net.Server" : "", "Xunit.KRunner": "0.1-alpha-*", "xunit.abstractions": "2.0.0-aspnet-*", "xunit.assert": "2.0.0-aspnet-*", "xunit.core": "2.0.0-aspnet-*", - "xunit.execution": "2.0.0-aspnet-*", - "Microsoft.Net.Server" : "", - "Microsoft.AspNet.Logging": "0.1-alpha-*" + "xunit.execution": "2.0.0-aspnet-*" }, "configurations": { "net45": { "dependencies": { - "System.Runtime": "", "System.Net.Http": "", - "System.Net.Http.WebRequest": "" + "System.Net.Http.WebRequest": "", + "System.Runtime": "" } } } From 587492738cb290f55cf479eabdc64dd9799c8188 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 8 May 2014 12:27:49 -0700 Subject: [PATCH 051/597] Remove unused dependency. --- test/Microsoft.Net.Server.FunctionalTests/Project.json | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Microsoft.Net.Server.FunctionalTests/Project.json b/test/Microsoft.Net.Server.FunctionalTests/Project.json index 410147cdf0..b49bc93e58 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Project.json +++ b/test/Microsoft.Net.Server.FunctionalTests/Project.json @@ -4,7 +4,6 @@ "test": "Xunit.KRunner" }, "dependencies": { - "Microsoft.AspNet.Logging": "0.1-alpha-*", "Microsoft.Net.Server" : "", "Xunit.KRunner": "0.1-alpha-*", "xunit.abstractions": "2.0.0-aspnet-*", From 332c1ce6758fef0b33e525f9e8763fbdad8ef018 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Thu, 8 May 2014 16:35:03 -0700 Subject: [PATCH 052/597] Create LICENSE.txt --- LICENSE.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000000..d85a1524ad --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,12 @@ +Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +these files except in compliance with the License. You may obtain a copy of the +License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. From ca89db04d45651cf89fff7e7cf2d334b40a97b3f Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 9 May 2014 01:08:30 -0700 Subject: [PATCH 053/597] React to renames --- WebListener.sln | 164 ++++++++++---------- samples/SelfHostServer/SelfHostServer.kproj | 3 + samples/SelfHostServer/Startup.cs | 2 +- 3 files changed, 86 insertions(+), 83 deletions(-) diff --git a/WebListener.sln b/WebListener.sln index c3c21e8fe7..26c7fe384f 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30401.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.21708.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -47,86 +47,86 @@ Global {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|x86.ActiveCfg = Release|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Any CPU.ActiveCfg = Debug|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|x86.ActiveCfg = Debug|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|x86.Build.0 = Debug|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Any CPU.ActiveCfg = Release|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Mixed Platforms.Build.0 = Release|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|x86.ActiveCfg = Release|x86 - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|x86.Build.0 = Release|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Any CPU.ActiveCfg = Debug|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|x86.ActiveCfg = Debug|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|x86.Build.0 = Debug|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Any CPU.ActiveCfg = Release|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Mixed Platforms.Build.0 = Release|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|x86.ActiveCfg = Release|x86 - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|x86.Build.0 = Release|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Any CPU.ActiveCfg = Debug|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|x86.ActiveCfg = Debug|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|x86.Build.0 = Debug|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Any CPU.ActiveCfg = Release|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.Build.0 = Release|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|x86.ActiveCfg = Release|x86 - {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|x86.Build.0 = Release|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Any CPU.ActiveCfg = Debug|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|x86.ActiveCfg = Debug|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|x86.Build.0 = Debug|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Any CPU.ActiveCfg = Release|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Mixed Platforms.Build.0 = Release|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|x86.ActiveCfg = Release|x86 - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|x86.Build.0 = Release|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Any CPU.ActiveCfg = Debug|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|x86.ActiveCfg = Debug|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|x86.Build.0 = Debug|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Any CPU.ActiveCfg = Release|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Mixed Platforms.Build.0 = Release|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|x86.ActiveCfg = Release|x86 - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|x86.Build.0 = Release|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Any CPU.ActiveCfg = Debug|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Debug|x86.ActiveCfg = Debug|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Debug|x86.Build.0 = Debug|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Release|Any CPU.ActiveCfg = Release|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Release|Mixed Platforms.Build.0 = Release|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Release|x86.ActiveCfg = Release|x86 - {4492FF4C-9032-411D-853F-46B01755E504}.Release|x86.Build.0 = Release|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Any CPU.ActiveCfg = Debug|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|x86.ActiveCfg = Debug|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|x86.Build.0 = Debug|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Any CPU.ActiveCfg = Release|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.Build.0 = Release|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|x86.ActiveCfg = Release|x86 - {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|x86.Build.0 = Release|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Any CPU.ActiveCfg = Debug|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|x86.ActiveCfg = Debug|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|x86.Build.0 = Debug|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Any CPU.ActiveCfg = Release|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.Build.0 = Release|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|x86.ActiveCfg = Release|x86 - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|x86.Build.0 = Release|x86 + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|x86.ActiveCfg = Debug|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Any CPU.Build.0 = Release|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|x86.ActiveCfg = Release|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|x86.ActiveCfg = Debug|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Any CPU.Build.0 = Release|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|x86.ActiveCfg = Release|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|x86.ActiveCfg = Debug|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Any CPU.Build.0 = Release|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|x86.ActiveCfg = Release|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|x86.ActiveCfg = Debug|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Any CPU.Build.0 = Release|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|x86.ActiveCfg = Release|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|x86.ActiveCfg = Debug|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Any CPU.Build.0 = Release|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|x86.ActiveCfg = Release|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Debug|x86.ActiveCfg = Debug|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Release|Any CPU.Build.0 = Release|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4492FF4C-9032-411D-853F-46B01755E504}.Release|x86.ActiveCfg = Release|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Debug|x86.ActiveCfg = Debug|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Any CPU.Build.0 = Release|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|x86.ActiveCfg = Release|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|x86.ActiveCfg = Debug|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Any CPU.Build.0 = Release|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index 2da6845307..65e1d26da7 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -16,6 +16,9 @@ 2.0 + + 57504 + diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index e37f198434..6b5f26b1d0 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -25,7 +25,7 @@ namespace SelfHostServer { public class Startup { - public void Configuration(IBuilder app) + public void Configure(IBuilder app) { var info = (ServerInformation)app.Server; info.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationType.None; From 475294688e9a6c48bef15d065c65c63f7ac8d343 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Sun, 18 May 2014 20:13:57 -0700 Subject: [PATCH 054/597] Updating kproj file to match tooling changes --- .gitignore | 3 ++- samples/HelloWorld/HelloWorld.kproj | 6 +++--- samples/SelfHostServer/SelfHostServer.kproj | 6 +++--- .../Microsoft.AspNet.Security.Windows.kproj | 6 +++--- .../Microsoft.AspNet.Server.WebListener.kproj | 6 +++--- .../Microsoft.AspNet.WebSockets.kproj | 6 +++--- src/Microsoft.Net.Server/Microsoft.Net.Server.kproj | 6 +++--- ...icrosoft.AspNet.Server.WebListener.FunctionalTests.kproj | 6 +++--- .../Microsoft.Net.Server.FunctionalTests.kproj | 6 +++--- 9 files changed, 26 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index aba9c594d7..08e21e25bf 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ nuget.exe *DS_Store *.ncrunchsolution *.*sdf -*.ipch \ No newline at end of file +*.ipch +*.sln.ide \ No newline at end of file diff --git a/samples/HelloWorld/HelloWorld.kproj b/samples/HelloWorld/HelloWorld.kproj index 878b876200..4573f3695d 100644 --- a/samples/HelloWorld/HelloWorld.kproj +++ b/samples/HelloWorld/HelloWorld.kproj @@ -1,10 +1,10 @@ - + 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 6daf3e6b-8e1b-4e6e-b9fe-7b1e5fdb7db4 Library @@ -22,5 +22,5 @@ - + \ No newline at end of file diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index 65e1d26da7..0253f96a4f 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -1,10 +1,10 @@ - + 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 1236f93a-ac5c-4a77-9477-c88f040151ca Library @@ -27,5 +27,5 @@ - + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj index 8f9815d39d..b3eb5ecaad 100644 --- a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj +++ b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj @@ -1,10 +1,10 @@ - + 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + efc7538f-7aeb-4a3e-a1e6-6bdccbd272bf Library @@ -69,5 +69,5 @@ - + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj index 2114c166fd..093e099abb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -1,10 +1,10 @@ - + 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + b9f45f9d-d206-47f0-8e5f-54ce2f0bdf92 Library @@ -28,5 +28,5 @@ - + \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj b/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj index f584e250bb..f1d3cb3339 100644 --- a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj +++ b/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj @@ -1,10 +1,10 @@ - + 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + e788aeae-2cb4-4bfa-8746-d0bb7e93a1bb Library @@ -54,5 +54,5 @@ - + \ No newline at end of file diff --git a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj index 93c2bc3c87..478fe0e4a2 100644 --- a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj +++ b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj @@ -1,10 +1,10 @@ - + 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 Library @@ -84,5 +84,5 @@ - + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj index 7e4afa0aed..5484b0f2c5 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj @@ -1,10 +1,10 @@ - + 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 4492ff4c-9032-411d-853f-46b01755e504 Library @@ -35,5 +35,5 @@ - + \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj index 93b8944285..1feb8f355c 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj +++ b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj @@ -1,10 +1,10 @@ - + 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + dcb6e0b1-223d-44e6-8696-4767e5b6e6a1 Library @@ -35,5 +35,5 @@ - + \ No newline at end of file From 88b0c498d69936aa270a68b63efa6d39dcdadb8f Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 25 May 2014 10:07:13 -0700 Subject: [PATCH 055/597] Renamed Project.json to Project.json2 --- src/Microsoft.Net.Server/{Project.json => Project.json2} | 0 .../{Project.json => Project.json2} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/Microsoft.Net.Server/{Project.json => Project.json2} (100%) rename test/Microsoft.Net.Server.FunctionalTests/{Project.json => Project.json2} (100%) diff --git a/src/Microsoft.Net.Server/Project.json b/src/Microsoft.Net.Server/Project.json2 similarity index 100% rename from src/Microsoft.Net.Server/Project.json rename to src/Microsoft.Net.Server/Project.json2 diff --git a/test/Microsoft.Net.Server.FunctionalTests/Project.json b/test/Microsoft.Net.Server.FunctionalTests/Project.json2 similarity index 100% rename from test/Microsoft.Net.Server.FunctionalTests/Project.json rename to test/Microsoft.Net.Server.FunctionalTests/Project.json2 From 66ea95eb497c6e18333c8f03c615a1a38036d893 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 25 May 2014 10:07:13 -0700 Subject: [PATCH 056/597] Fixed casing of project.json --- src/Microsoft.Net.Server/{Project.json2 => project.json} | 0 .../{Project.json2 => project.json} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/Microsoft.Net.Server/{Project.json2 => project.json} (100%) rename test/Microsoft.Net.Server.FunctionalTests/{Project.json2 => project.json} (100%) diff --git a/src/Microsoft.Net.Server/Project.json2 b/src/Microsoft.Net.Server/project.json similarity index 100% rename from src/Microsoft.Net.Server/Project.json2 rename to src/Microsoft.Net.Server/project.json diff --git a/test/Microsoft.Net.Server.FunctionalTests/Project.json2 b/test/Microsoft.Net.Server.FunctionalTests/project.json similarity index 100% rename from test/Microsoft.Net.Server.FunctionalTests/Project.json2 rename to test/Microsoft.Net.Server.FunctionalTests/project.json From 60812e51f1ebcfcc5a380b7fa48dcb933e04594a Mon Sep 17 00:00:00 2001 From: David Fowler Date: Mon, 26 May 2014 02:55:37 -0700 Subject: [PATCH 057/597] Fixed project.json casing in kproj --- samples/HelloWorld/HelloWorld.kproj | 7 ++++--- samples/SelfHostServer/SelfHostServer.kproj | 7 ++++--- .../Microsoft.AspNet.Security.Windows.kproj | 7 ++++--- .../Microsoft.AspNet.Server.WebListener.kproj | 7 ++++--- .../Microsoft.AspNet.WebSockets.kproj | 7 ++++--- src/Microsoft.Net.Server/Microsoft.Net.Server.kproj | 7 ++++--- ...crosoft.AspNet.Server.WebListener.FunctionalTests.kproj | 7 ++++--- .../Microsoft.Net.Server.FunctionalTests.kproj | 7 ++++--- 8 files changed, 32 insertions(+), 24 deletions(-) diff --git a/samples/HelloWorld/HelloWorld.kproj b/samples/HelloWorld/HelloWorld.kproj index 4573f3695d..d0e521b2a1 100644 --- a/samples/HelloWorld/HelloWorld.kproj +++ b/samples/HelloWorld/HelloWorld.kproj @@ -1,4 +1,4 @@ - + 12.0 @@ -17,10 +17,11 @@ 2.0 - + - \ No newline at end of file + + diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index 0253f96a4f..27e7adbaef 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -1,4 +1,4 @@ - + 12.0 @@ -21,11 +21,12 @@ - + - \ No newline at end of file + + diff --git a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj index b3eb5ecaad..3c5c6aba75 100644 --- a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj +++ b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj @@ -1,4 +1,4 @@ - + 12.0 @@ -18,7 +18,7 @@ 2.0 - + @@ -70,4 +70,5 @@ - \ No newline at end of file + + diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj index 093e099abb..1b81c12fac 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -1,4 +1,4 @@ - + 12.0 @@ -17,7 +17,7 @@ 2.0 - + @@ -29,4 +29,5 @@ - \ No newline at end of file + + diff --git a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj b/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj index f1d3cb3339..fb4bf3edd4 100644 --- a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj +++ b/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj @@ -1,4 +1,4 @@ - + 12.0 @@ -19,7 +19,7 @@ - + @@ -55,4 +55,5 @@ - \ No newline at end of file + + diff --git a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj index 478fe0e4a2..c1142c94f9 100644 --- a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj +++ b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj @@ -1,4 +1,4 @@ - + 12.0 @@ -80,9 +80,10 @@ - + - \ No newline at end of file + + diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj index 5484b0f2c5..6f6987bdb0 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj @@ -1,4 +1,4 @@ - + 12.0 @@ -33,7 +33,8 @@ - + - \ No newline at end of file + + diff --git a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj index 1feb8f355c..3de1aacf05 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj +++ b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj @@ -1,4 +1,4 @@ - + 12.0 @@ -33,7 +33,8 @@ - + - \ No newline at end of file + + From 9191bddf005f1582d23eb6b21f76e240d2a27b9d Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 30 May 2014 15:54:03 -0700 Subject: [PATCH 058/597] Wait for requests to drain during shutdown. --- .../MessagePump.cs | 38 ++++++++++++++++--- .../ServerTests.cs | 20 ++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index bcf7ba653f..890f9b9e63 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -39,6 +39,10 @@ namespace Microsoft.AspNet.Server.WebListener private int _acceptorCounts; private Action _processRequest; + private bool _stopping; + private int _outstandingRequests; + private ManualResetEvent _shutdownSignal; + // TODO: private IDictionary _capabilities; internal MessagePump(Microsoft.Net.Server.WebListener listener, ILoggerFactory loggerFactory) @@ -49,6 +53,7 @@ namespace Microsoft.AspNet.Server.WebListener _processRequest = new Action(ProcessRequestAsync); _maxAccepts = DefaultMaxAccepts; + _shutdownSignal = new ManualResetEvent(false); } internal Microsoft.Net.Server.WebListener Listener @@ -108,7 +113,7 @@ namespace Microsoft.AspNet.Server.WebListener private async void ProcessRequestsWorker() { int workerIndex = Interlocked.Increment(ref _acceptorCounts); - while (_listener.IsListening && workerIndex <= MaxAccepts) + while (!_stopping && workerIndex <= MaxAccepts) { // Receive a request RequestContext requestContext; @@ -124,7 +129,7 @@ namespace Microsoft.AspNet.Server.WebListener } try { - Task.Factory.StartNew(_processRequest, requestContext); + Task ignored = Task.Factory.StartNew(_processRequest, requestContext); } catch (Exception ex) { @@ -141,11 +146,18 @@ namespace Microsoft.AspNet.Server.WebListener var requestContext = requestContextObj as RequestContext; try { + if (_stopping) + { + SetFatalResponse(requestContext, 503); + return; + } try { + Interlocked.Increment(ref _outstandingRequests); FeatureContext featureContext = new FeatureContext(requestContext); await _appFunc(featureContext.Features).SupressContext(); // TODO: WebSocket/Opaque upgrade - await requestContext.ProcessResponseAsync().SupressContext(); + requestContext.Dispose(); } catch (Exception ex) { @@ -157,10 +169,16 @@ namespace Microsoft.AspNet.Server.WebListener else { // We haven't sent a response yet, try to send a 500 Internal Server Error - SetFatalResponse(requestContext); + SetFatalResponse(requestContext, 500); + } + } + finally + { + if (Interlocked.Decrement(ref _outstandingRequests) == 0 && _stopping) + { + _shutdownSignal.Set(); } } - requestContext.Dispose(); } catch (Exception ex) { @@ -169,16 +187,24 @@ namespace Microsoft.AspNet.Server.WebListener } } - private static void SetFatalResponse(RequestContext context) + private static void SetFatalResponse(RequestContext context, int status) { - context.Response.StatusCode = 500; + context.Response.StatusCode = status; context.Response.ReasonPhrase = string.Empty; context.Response.Headers.Clear(); context.Response.ContentLength = 0; + context.Dispose(); } public void Dispose() { + _stopping = true; + // Wait for active requests to drain + if (_outstandingRequests > 0) + { + _shutdownSignal.WaitOne(); + } + // All requests are finished _listener.Dispose(); } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index c6f47bb48c..0b84f3a63a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -80,6 +80,26 @@ namespace Microsoft.AspNet.Server.WebListener } } + [Fact] + public async Task Server_ShutdownDurringRequest_Success() + { + Task responseTask; + ManualResetEvent received = new ManualResetEvent(false); + using (Utilities.CreateHttpServer(env => + { + received.Set(); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); + })) + { + responseTask = SendRequestAsync(Address); + Assert.True(received.WaitOne(10000)); + } + string response = await responseTask; + Assert.Equal("Hello World", response); + } + [Fact] public void Server_AppException_ClientReset() { From 271a8714d863609b1c7976f596d217abff9192a8 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 2 Jun 2014 09:25:57 -0700 Subject: [PATCH 059/597] Remove ChannelBinding stub, it's now available. --- .../Microsoft.Net.Server.kproj | 4 +- .../SafeLocalFreeChannelBinding.cs | 8 +++ .../ExtendedProtection/ChannelBinding.cs | 50 ------------------- 3 files changed, 9 insertions(+), 53 deletions(-) delete mode 100644 src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs diff --git a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj index c1142c94f9..7c64fe5b48 100644 --- a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj +++ b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj @@ -29,7 +29,6 @@ - @@ -85,5 +84,4 @@ - - + \ No newline at end of file diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs index eab0a03105..be210bbdf1 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs +++ b/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -55,5 +55,13 @@ namespace Microsoft.Net.Server { return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; } + + public override bool IsInvalid + { + get + { + return handle == IntPtr.Zero || handle.ToInt32() == -1; + } + } } } diff --git a/src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs b/src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs deleted file mode 100644 index cefd0e12f3..0000000000 --- a/src/Microsoft.Net.Server/fx/System/Security/Authentication/ExtendedProtection/ChannelBinding.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System.Runtime.InteropServices; -using Microsoft.Win32.SafeHandles; - -#if !NET45 - -namespace System.Security.Authentication.ExtendedProtection -{ - internal abstract class ChannelBinding : SafeHandleZeroOrMinusOneIsInvalid - { - protected ChannelBinding() - : base(true) - { - } - - protected ChannelBinding(bool ownsHandle) - : base(ownsHandle) - { - } - - public abstract int Size - { - get; - } - } -} - -#endif \ No newline at end of file From d1aed15ec409ed0ddeb9bac0893f5826228df0ba Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 3 Jun 2014 10:17:34 -0700 Subject: [PATCH 060/597] Adding switch to build.cmd to skip KRE install --- build.cmd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.cmd b/build.cmd index 903d532df3..3aaf957583 100644 --- a/build.cmd +++ b/build.cmd @@ -18,6 +18,8 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion + +IF "%SKIP_KRE_INSTALL%"=="1" goto run CALL packages\KoreBuild\build\kvm upgrade -svr50 -x86 CALL packages\KoreBuild\build\kvm install default -svrc50 -x86 From b7f2981a6cf1409bd13a7185e2ff7a2f8f4c1c6e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 10 Jun 2014 17:25:08 -0700 Subject: [PATCH 061/597] Updating build.sh based on KRuntime changes --- build.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index db1e0c3dde..4323aefc48 100644 --- a/build.sh +++ b/build.sh @@ -3,10 +3,10 @@ if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild else - if x$XDG_DATA_HOME = x; then - cachedir=$HOME/.local/share + if [ -z $XDG_DATA_HOME ]; then + cachedir=$HOME/.local/share else - cachedir=$XDG_DATA_HOME; + cachedir=$XDG_DATA_HOME; fi fi mkdir -p $cachedir @@ -14,12 +14,12 @@ mkdir -p $cachedir url=https://www.nuget.org/nuget.exe if test ! -f $cachedir/nuget.exe; then - wget -o $cachedir/nuget.exe $url 2>/dev/null || curl -o $cachedir/nuget.exe --location $url /dev/null + wget -O $cachedir/nuget.exe $url 2>/dev/null || curl -o $cachedir/nuget.exe --location $url /dev/null fi if test ! -e .nuget; then mkdir .nuget - cp $cachedir/nuget.exe .nuget + cp $cachedir/nuget.exe .nuget/nuget.exe fi if test ! -d packages/KoreBuild; then @@ -27,4 +27,12 @@ if test ! -d packages/KoreBuild; then mono .nuget/nuget.exe install Sake -version 0.2 -o packages -ExcludeVersion fi -mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" \ No newline at end of file +if ! type k > /dev/null 2>&1; then + source setup/kvm.sh +fi + +if ! type k > /dev/null 2>&1; then + kvm upgrade +fi + +mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" From 1ef31a943a589fc2dd103790ee050a309e59bd02 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 18 Jun 2014 16:49:26 -0700 Subject: [PATCH 062/597] Change the default author in makefile.shade --- makefile.shade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile.shade b/makefile.shade index 6357ea2841..562494d144 100644 --- a/makefile.shade +++ b/makefile.shade @@ -1,7 +1,7 @@ var VERSION='0.1' var FULL_VERSION='0.1' -var AUTHORS='Microsoft' +var AUTHORS='Microsoft Open Technologies, Inc.' use-standard-lifecycle k-standard-goals From d1dab1665e40c5dd7c62ede996f1ed3fb1a4d35c Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 16 Jun 2014 14:24:20 -0700 Subject: [PATCH 063/597] Expose Opaque and WebSockets. --- WebListener.sln | 4 +- samples/HelloWorld/Program.cs | 22 +- samples/SelfHostServer/Startup.cs | 20 +- samples/SelfHostServer/project.json | 2 +- .../FeatureContext.cs | 62 +++- .../MessagePump.cs | 1 - .../project.json | 3 + src/Microsoft.AspNet.WebSockets/Constants.cs | 36 --- .../Legacy/HttpListenerContext.cs | 75 ----- .../Legacy/HttpListenerRequest.cs | 83 ----- .../OwinWebSocketWrapper.cs | 152 --------- src/Microsoft.AspNet.WebSockets/WebSocket.cs | 141 --------- .../WebSocketCloseStatus.cs | 57 ---- .../WebSocketExtensions.cs | 32 -- .../WebSocketMessageType.cs | 32 -- .../WebSocketMiddleware.cs | 185 ----------- .../WebSocketReceiveResult.cs | 72 ----- .../WebSocketState.cs | 36 --- src/Microsoft.AspNet.WebSockets/project.json | 14 - .../RequestProcessing/Request.cs | 11 + .../RequestProcessing/RequestContext.cs | 288 ++++++++++++++---- src/Microsoft.Net.Server/project.json | 4 +- .../HttpKnownHeaderNames.cs | 2 +- .../Legacy/SR.cs | 0 .../WebSocketHttpListenerDuplexStream.cs | 0 .../Microsoft.Net.WebSockets.kproj} | 15 +- .../NativeInterop/SafeLoadLibrary.cs | 2 +- .../NativeInterop/SafeNativeOverlapped.cs | 2 +- .../NativeInterop/SafeWebSocketHandle.cs | 3 +- .../NativeInterop/UnsafeNativeMethods.cs | 6 +- .../ServerWebSocket.cs | 2 +- .../WebSocketBase.cs | 37 +-- .../WebSocketBuffer.cs | 13 +- .../WebSocketConstants.cs | 9 + .../WebSocketError.cs | 2 +- .../WebSocketException.cs | 3 +- .../WebSocketHelpers.cs | 255 ++++------------ .../WebSocketMiddleware.cs | 159 ++++++++++ .../WebSocketReceiveResultExtensions.cs | 49 +++ .../build.cmd | 0 .../SafeHandleZeroOrMinusOneIsInvalid.cs | 0 .../fx/System/AccessViolationException.cs | 0 .../System/ComponentModel/Win32Exception.cs | 0 .../fx/System/ExternDll.cs | 0 .../InteropServices/ExternalException.cs | 0 .../fx/System/SafeNativeMethods.cs | 0 .../fx/System/SystemException.cs | 0 src/Microsoft.Net.WebSockets/project.json | 39 +++ 48 files changed, 697 insertions(+), 1233 deletions(-) delete mode 100644 src/Microsoft.AspNet.WebSockets/Constants.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/WebSocket.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/WebSocketState.cs delete mode 100644 src/Microsoft.AspNet.WebSockets/project.json rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/HttpKnownHeaderNames.cs (99%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/Legacy/SR.cs (100%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/Legacy/WebSocketHttpListenerDuplexStream.cs (100%) rename src/{Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj => Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj} (83%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/NativeInterop/SafeLoadLibrary.cs (98%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/NativeInterop/SafeNativeOverlapped.cs (98%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/NativeInterop/SafeWebSocketHandle.cs (96%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/NativeInterop/UnsafeNativeMethods.cs (99%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/ServerWebSocket.cs (98%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/WebSocketBase.cs (98%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/WebSocketBuffer.cs (98%) create mode 100644 src/Microsoft.Net.WebSockets/WebSocketConstants.cs rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/WebSocketError.cs (97%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/WebSocketException.cs (99%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/WebSocketHelpers.cs (58%) create mode 100644 src/Microsoft.Net.WebSockets/WebSocketMiddleware.cs create mode 100644 src/Microsoft.Net.WebSockets/WebSocketReceiveResultExtensions.cs rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/build.cmd (100%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs (100%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/fx/System/AccessViolationException.cs (100%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/fx/System/ComponentModel/Win32Exception.cs (100%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/fx/System/ExternDll.cs (100%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/fx/System/Runtime/InteropServices/ExternalException.cs (100%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/fx/System/SafeNativeMethods.cs (100%) rename src/{Microsoft.AspNet.WebSockets => Microsoft.Net.WebSockets}/fx/System/SystemException.cs (100%) create mode 100644 src/Microsoft.Net.WebSockets/project.json diff --git a/WebListener.sln b/WebListener.sln index 26c7fe384f..3846c0df71 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.21708.0 +VisualStudioVersion = 14.0.21730.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -19,7 +19,7 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\S EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Security.Windows", "src\Microsoft.AspNet.Security.Windows\Microsoft.AspNet.Security.Windows.kproj", "{EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.WebSockets", "src\Microsoft.AspNet.WebSockets\Microsoft.AspNet.WebSockets.kproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.WebSockets", "src\Microsoft.Net.WebSockets\Microsoft.Net.WebSockets.kproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj", "{4492FF4C-9032-411D-853F-46B01755E504}" EndProject diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index d411f251a0..65336e9be3 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -16,7 +16,9 @@ // permissions and limitations under the License. using System; +using System.Net.WebSockets; using System.Text; +using System.Threading; using Microsoft.Net.Server; namespace HelloWorld @@ -73,11 +75,23 @@ namespace HelloWorld // Response byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); - context.Response.ContentLength = bytes.Length; - context.Response.ContentType = "text/plain"; + if (context.IsWebSocketRequest) + { + Console.WriteLine("WebSocket"); + WebSocket webSocket = context.AcceptWebSocketAsync().Result; + webSocket.SendAsync(new ArraySegment(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None).Wait(); + webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Goodbye", CancellationToken.None).Wait(); + webSocket.Dispose(); + } + else + { + Console.WriteLine("Hello World"); + context.Response.ContentLength = bytes.Length; + context.Response.ContentType = "text/plain"; - context.Response.Body.Write(bytes, 0, bytes.Length); - context.Dispose(); + context.Response.Body.Write(bytes, 0, bytes.Length); + context.Dispose(); + } } } } diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 6b5f26b1d0..3a6c87a4ab 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -15,6 +15,10 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. +using System; +using System.Net.WebSockets; +using System.Text; +using System.Threading; using Microsoft.AspNet; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; @@ -32,8 +36,20 @@ namespace SelfHostServer app.Run(async context => { - context.Response.ContentType = "text/plain"; - await context.Response.WriteAsync("Hello world"); + if (context.IsWebSocketRequest) + { + Console.WriteLine("WebSocket"); + byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); + WebSocket webSocket = await context.AcceptWebSocketAsync(); + await webSocket.SendAsync(new ArraySegment(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None); + await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Goodbye", CancellationToken.None); + webSocket.Dispose(); + } + else + { + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Hello world"); + } }); } } diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 9945c5dac2..002bc7304b 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -6,7 +6,7 @@ "Microsoft.AspNet.Server.WebListener": "", "Microsoft.Net.Server": "" }, - "commands": { "web": "Microsoft.AspNet.Hosting server.name=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001" }, + "commands": { "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:8080" }, "configurations": { "net45": { }, diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index e217b38495..720ed6e51c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.WebSockets; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; @@ -28,7 +29,15 @@ using Microsoft.Net.Server; namespace Microsoft.AspNet.Server.WebListener { - internal class FeatureContext : IHttpRequestFeature, IHttpConnectionFeature, IHttpResponseFeature, IHttpSendFileFeature, IHttpTransportLayerSecurityFeature, IHttpRequestLifetimeFeature + internal class FeatureContext : + IHttpRequestFeature, + IHttpConnectionFeature, + IHttpResponseFeature, + IHttpSendFileFeature, + IHttpTransportLayerSecurityFeature, + IHttpRequestLifetimeFeature, + IHttpWebSocketFeature, + IHttpOpaqueUpgradeFeature { private RequestContext _requestContext; private FeatureCollection _features; @@ -85,10 +94,13 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpSendFileFeature), this); _features.Add(typeof(IHttpRequestLifetimeFeature), this); + // TODO: If Win8+ + _features.Add(typeof(IHttpOpaqueUpgradeFeature), this); + _features.Add(typeof(IHttpWebSocketFeature), this); + // TODO: // _environment.CallCancelled = _cts.Token; // _environment.User = _request.User; - // Opaque/WebSockets // Channel binding /* @@ -348,11 +360,16 @@ namespace Microsoft.AspNet.Server.WebListener set { Response.StatusCode = value; } } #endregion + #region IHttpSendFileFeature + Task IHttpSendFileFeature.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) { return Response.SendFileAsync(path, offset, length, cancellation); } + #endregion + #region IHttpRequestLifetimeFeature + public CancellationToken OnRequestAborted { get { return _requestContext.DisconnectToken; } @@ -362,5 +379,46 @@ namespace Microsoft.AspNet.Server.WebListener { _requestContext.Abort(); } + + #endregion + #region IHttpOpaqueUpgradeFeature + + public bool IsUpgradableRequest + { + get { return _requestContext.IsUpgradableRequest; } + } + + public Task UpgradeAsync() + { + if (!IsUpgradableRequest) + { + throw new InvalidOperationException("This request cannot be upgraded."); + } + return _requestContext.UpgradeAsync(); + } + + #endregion + #region IHttpWebSocketFeature + + public bool IsWebSocketRequest + { + get + { + return _requestContext.IsWebSocketRequest; + } + } + + public Task AcceptAsync(IWebSocketAcceptContext context) + { + // TODO: Advanced params + string subProtocol = null; + if (context != null) + { + subProtocol = context.SubProtocol; + } + return _requestContext.AcceptWebSocketAsync(subProtocol); + } + + #endregion } } diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index 890f9b9e63..f1de9d6423 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -156,7 +156,6 @@ namespace Microsoft.AspNet.Server.WebListener Interlocked.Increment(ref _outstandingRequests); FeatureContext featureContext = new FeatureContext(requestContext); await _appFunc(featureContext.Features).SupressContext(); - // TODO: WebSocket/Opaque upgrade - await requestContext.ProcessResponseAsync().SupressContext(); requestContext.Dispose(); } catch (Exception ex) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 459e0d16de..e7840b9642 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -16,6 +16,7 @@ "net45": {}, "k10": { "dependencies": { + "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*", "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.0.0", "System.Collections.Concurrent": "4.0.0.0", @@ -25,12 +26,14 @@ "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", "System.Linq": "4.0.0.0", + "System.Net.Primitives": "4.0.10.0", "System.Reflection": "4.0.10.0", "System.Resources.ResourceManager": "4.0.0.0", "System.Runtime": "4.0.20.0", "System.Runtime.Extensions": "4.0.10.0", "System.Runtime.Handles": "4.0.0.0", "System.Runtime.InteropServices": "4.0.20.0", + "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", "System.Text.Encoding.Extensions": "4.0.10.0", diff --git a/src/Microsoft.AspNet.WebSockets/Constants.cs b/src/Microsoft.AspNet.WebSockets/Constants.cs deleted file mode 100644 index 8f4e0df564..0000000000 --- a/src/Microsoft.AspNet.WebSockets/Constants.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -namespace Microsoft.AspNet.WebSockets -{ - /// - /// Standard keys and values for use within the OWIN interfaces - /// - internal static class Constants - { - internal const string WebSocketAcceptKey = "websocket.Accept"; - internal const string WebSocketSubProtocolKey = "websocket.SubProtocol"; - internal const string WebSocketSendAsyncKey = "websocket.SendAsync"; - internal const string WebSocketReceiveAyncKey = "websocket.ReceiveAsync"; - internal const string WebSocketCloseAsyncKey = "websocket.CloseAsync"; - internal const string WebSocketCallCancelledKey = "websocket.CallCancelled"; - internal const string WebSocketVersionKey = "websocket.Version"; - internal const string WebSocketVersion = "1.0"; - internal const string WebSocketCloseStatusKey = "websocket.ClientCloseStatus"; - internal const string WebSocketCloseDescriptionKey = "websocket.ClientCloseDescription"; - } -} diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs deleted file mode 100644 index 891c8739f7..0000000000 --- a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerContext.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ -/* -namespace Microsoft.Net -{ - using Microsoft.AspNet.WebSockets; - using System; - using System.ComponentModel; - using System.Threading.Tasks; - - public sealed unsafe class HttpListenerContext { - private HttpListenerRequest m_Request; - - public Task AcceptWebSocketAsync(string subProtocol) - { - return this.AcceptWebSocketAsync(subProtocol, - WebSocketHelpers.DefaultReceiveBufferSize, - WebSocket.DefaultKeepAliveInterval); - } - - public Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval) - { - return this.AcceptWebSocketAsync(subProtocol, - WebSocketHelpers.DefaultReceiveBufferSize, - keepAliveInterval); - } - - public Task AcceptWebSocketAsync(string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval) - { - WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); - - ArraySegment internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - return this.AcceptWebSocketAsync(subProtocol, - receiveBufferSize, - keepAliveInterval, - internalBuffer); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public Task AcceptWebSocketAsync(string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) - { - return WebSocketHelpers.AcceptWebSocketAsync(this, - subProtocol, - receiveBufferSize, - keepAliveInterval, - internalBuffer); - } - } -} -*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs b/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs deleted file mode 100644 index 41a6c1a6a6..0000000000 --- a/src/Microsoft.AspNet.WebSockets/Legacy/HttpListenerRequest.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -/* -namespace Microsoft.Net -{ - using System; - using System.Collections; - using System.Collections.Specialized; - using System.IO; - using System.Runtime.InteropServices; - using System.Globalization; - using System.Text; - using System.Security.Principal; - using System.Security.Cryptography.X509Certificates; - using System.Net; - using Microsoft.AspNet.WebSockets; - - public sealed unsafe class HttpListenerRequest { - - public bool IsWebSocketRequest - { - get - { - if (!WebSocketProtocolComponent.IsSupported) - { - return false; - } - - bool foundConnectionUpgradeHeader = false; - if (string.IsNullOrEmpty(this.Headers[HttpKnownHeaderNames.Connection]) || string.IsNullOrEmpty(this.Headers[HttpKnownHeaderNames.Upgrade])) - { - return false; - } - - foreach (string connection in this.Headers.GetValues(HttpKnownHeaderNames.Connection)) - { - if (string.Compare(connection, HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) == 0) - { - foundConnectionUpgradeHeader = true; - break; - } - } - - if (!foundConnectionUpgradeHeader) - { - return false; - } - - foreach (string upgrade in this.Headers.GetValues(HttpKnownHeaderNames.Upgrade)) - { - if (string.Compare(upgrade, WebSocketHelpers.WebSocketUpgradeToken, StringComparison.OrdinalIgnoreCase) == 0) - { - return true; - } - } - - return false; - } - } - } -} -*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs b/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs deleted file mode 100644 index 5947567acf..0000000000 --- a/src/Microsoft.AspNet.WebSockets/OwinWebSocketWrapper.cs +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.AspNet.WebSockets -{ - using WebSocketCloseAsync = - Func; - using WebSocketReceiveAsync = - Func /* data */, - CancellationToken /* cancel */, - Task>>; - using WebSocketReceiveTuple = - Tuple; - using WebSocketSendAsync = - Func /* data */, - int /* messageType */, - bool /* endOfMessage */, - CancellationToken /* cancel */, - Task>; - - internal class OwinWebSocketWrapper - { - private readonly WebSocket _webSocket; - private readonly IDictionary _environment; - private readonly CancellationToken _cancellationToken; - - internal OwinWebSocketWrapper(WebSocket webSocket, CancellationToken ct) - { - _webSocket = webSocket; - _cancellationToken = ct; - - _environment = new Dictionary(); - _environment[Constants.WebSocketSendAsyncKey] = new WebSocketSendAsync(SendAsync); - _environment[Constants.WebSocketReceiveAyncKey] = new WebSocketReceiveAsync(ReceiveAsync); - _environment[Constants.WebSocketCloseAsyncKey] = new WebSocketCloseAsync(CloseAsync); - _environment[Constants.WebSocketCallCancelledKey] = ct; - _environment[Constants.WebSocketVersionKey] = Constants.WebSocketVersion; - } - - internal IDictionary Environment - { - get { return _environment; } - } - - internal Task SendAsync(ArraySegment buffer, int messageType, bool endOfMessage, CancellationToken cancel) - { - // Remap close messages to CloseAsync. System.Net.WebSockets.WebSocket.SendAsync does not allow close messages. - if (messageType == 0x8) - { - return RedirectSendToCloseAsync(buffer, cancel); - } - else if (messageType == 0x9 || messageType == 0xA) - { - // Ping & Pong, not allowed by the underlying APIs, silently discard. - return Task.FromResult(0); - } - - return _webSocket.SendAsync(buffer, (WebSocketMessageType)messageType, endOfMessage, cancel); - } - - internal async Task ReceiveAsync(ArraySegment buffer, CancellationToken cancel) - { - WebSocketReceiveResult nativeResult = await _webSocket.ReceiveAsync(buffer, cancel); - - if (nativeResult.MessageType == WebSocketMessageType.Close) - { - _environment[Constants.WebSocketCloseStatusKey] = (int)(nativeResult.CloseStatus ?? WebSocketCloseStatus.NormalClosure); - _environment[Constants.WebSocketCloseDescriptionKey] = nativeResult.CloseStatusDescription ?? string.Empty; - } - - return new WebSocketReceiveTuple( - (int)nativeResult.MessageType, - nativeResult.EndOfMessage, - nativeResult.Count); - } - - internal Task CloseAsync(int status, string description, CancellationToken cancel) - { - return _webSocket.CloseOutputAsync((WebSocketCloseStatus)status, description, cancel); - } - - private Task RedirectSendToCloseAsync(ArraySegment buffer, CancellationToken cancel) - { - if (buffer.Array == null || buffer.Count == 0) - { - return CloseAsync(1000, string.Empty, cancel); - } - else if (buffer.Count >= 2) - { - // Unpack the close message. - int statusCode = - (buffer.Array[buffer.Offset] << 8) - | buffer.Array[buffer.Offset + 1]; - string description = Encoding.UTF8.GetString(buffer.Array, buffer.Offset + 2, buffer.Count - 2); - - return CloseAsync(statusCode, description, cancel); - } - else - { - throw new ArgumentOutOfRangeException("buffer"); - } - } - - internal async Task CleanupAsync() - { - switch (_webSocket.State) - { - case WebSocketState.Closed: // Closed gracefully, no action needed. - case WebSocketState.Aborted: // Closed abortively, no action needed. - break; - case WebSocketState.CloseReceived: - // Echo what the client said, if anything. - await _webSocket.CloseAsync(_webSocket.CloseStatus ?? WebSocketCloseStatus.NormalClosure, - _webSocket.CloseStatusDescription ?? string.Empty, _cancellationToken); - break; - case WebSocketState.Open: - case WebSocketState.CloseSent: // No close received, abort so we don't have to drain the pipe. - _webSocket.Abort(); - break; - default: - throw new ArgumentOutOfRangeException("state", _webSocket.State, string.Empty); - } - } - } -} diff --git a/src/Microsoft.AspNet.WebSockets/WebSocket.cs b/src/Microsoft.AspNet.WebSockets/WebSocket.cs deleted file mode 100644 index 8050263d87..0000000000 --- a/src/Microsoft.AspNet.WebSockets/WebSocket.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.AspNet.WebSockets -{ - public abstract class WebSocket : IDisposable - { - private static TimeSpan? defaultKeepAliveInterval; - - public abstract WebSocketCloseStatus? CloseStatus { get; } - public abstract string CloseStatusDescription { get; } - public abstract string SubProtocol { get; } - public abstract WebSocketState State { get; } - - public static TimeSpan DefaultKeepAliveInterval - { - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", - Justification = "This is a harmless read-only operation")] - get - { - if (defaultKeepAliveInterval == null) - { - if (UnsafeNativeMethods.WebSocketProtocolComponent.IsSupported) - { - defaultKeepAliveInterval = UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketGetDefaultKeepAliveInterval(); - } - else - { - defaultKeepAliveInterval = Timeout.InfiniteTimeSpan; - } - } - return defaultKeepAliveInterval.Value; - } - } - - public static ArraySegment CreateClientBuffer(int receiveBufferSize, int sendBufferSize) - { - WebSocketHelpers.ValidateBufferSizes(receiveBufferSize, sendBufferSize); - - return WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, sendBufferSize, false); - } - - public static ArraySegment CreateServerBuffer(int receiveBufferSize) - { - WebSocketHelpers.ValidateBufferSizes(receiveBufferSize, WebSocketBuffer.MinSendBufferSize); - - return WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - } - - internal static WebSocket CreateServerWebSocket(Stream innerStream, - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) - { - if (!UnsafeNativeMethods.WebSocketProtocolComponent.IsSupported) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - WebSocketHelpers.ValidateInnerStream(innerStream); - WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); - WebSocketHelpers.ValidateArraySegment(internalBuffer, "internalBuffer"); - WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - - return new ServerWebSocket(innerStream, - subProtocol, - receiveBufferSize, - keepAliveInterval, - internalBuffer); - } - - public abstract void Abort(); - public abstract Task CloseAsync(WebSocketCloseStatus closeStatus, - string statusDescription, - CancellationToken cancellationToken); - public abstract Task CloseOutputAsync(WebSocketCloseStatus closeStatus, - string statusDescription, - CancellationToken cancellationToken); - [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "This rule is outdated")] - public abstract void Dispose(); - public abstract Task ReceiveAsync(ArraySegment buffer, - CancellationToken cancellationToken); - public abstract Task SendAsync(ArraySegment buffer, - WebSocketMessageType messageType, - bool endOfMessage, - CancellationToken cancellationToken); - - protected static void ThrowOnInvalidState(WebSocketState state, params WebSocketState[] validStates) - { - string validStatesText = string.Empty; - - if (validStates != null && validStates.Length > 0) - { - foreach (WebSocketState currentState in validStates) - { - if (state == currentState) - { - return; - } - } - - validStatesText = string.Join(", ", validStates); - } - - throw new WebSocketException(SR.GetString(SR.net_WebSockets_InvalidState, state, validStatesText)); - } - - protected static bool IsStateTerminal(WebSocketState state) - { - return state == WebSocketState.Closed || - state == WebSocketState.Aborted; - } - } -} diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs b/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs deleted file mode 100644 index 313efa3507..0000000000 --- a/src/Microsoft.AspNet.WebSockets/WebSocketCloseStatus.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Microsoft.AspNet.WebSockets -{ - [SuppressMessage("Microsoft.Design", - "CA1008:EnumsShouldHaveZeroValue", - Justification = "This enum is reflecting the IETF's WebSocket specification. " + - "'0' is a disallowed value for the close status code")] - public enum WebSocketCloseStatus - { - NormalClosure = 1000, - EndpointUnavailable = 1001, - ProtocolError = 1002, - InvalidMessageType = 1003, - Empty = 1005, - // AbnormalClosure = 1006, // 1006 is reserved and should never be used by user - InvalidPayloadData = 1007, - PolicyViolation = 1008, - MessageTooBig = 1009, - MandatoryExtension = 1010, - InternalServerError = 1011 - // TLSHandshakeFailed = 1015, // 1015 is reserved and should never be used by user - - // 0 - 999 Status codes in the range 0-999 are not used. - // 1000 - 1999 Status codes in the range 1000-1999 are reserved for definition by this protocol. - // 2000 - 2999 Status codes in the range 2000-2999 are reserved for use by extensions. - // 3000 - 3999 Status codes in the range 3000-3999 MAY be used by libraries and frameworks. The - // interpretation of these codes is undefined by this protocol. End applications MUST - // NOT use status codes in this range. - // 4000 - 4999 Status codes in the range 4000-4999 MAY be used by application code. The interpretaion - // of these codes is undefined by this protocol. - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs b/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs deleted file mode 100644 index ccacef2231..0000000000 --- a/src/Microsoft.AspNet.WebSockets/WebSocketExtensions.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. -/* -#if NET45 -using Microsoft.AspNet.WebSockets; - -namespace Owin -{ - public static class WebSocketExtensions - { - public static IAppBuilder UseWebSockets(this IAppBuilder app) - { - return app.Use(); - } - } -} -#endif -*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs b/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs deleted file mode 100644 index 2c362f7299..0000000000 --- a/src/Microsoft.AspNet.WebSockets/WebSocketMessageType.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.AspNet.WebSockets -{ - public enum WebSocketMessageType - { - Text = 0x1, - Binary = 0x2, - Close = 0x8, - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs b/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs deleted file mode 100644 index 8ed52f1ba7..0000000000 --- a/src/Microsoft.AspNet.WebSockets/WebSocketMiddleware.cs +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. -/* -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Owin; - -namespace Microsoft.AspNet.WebSockets -{ - using AppFunc = Func, Task>; - using OpaqueUpgrade = - Action - < - IDictionary, // Parameters - Func // OpaqueFunc callback - < - IDictionary, // Opaque environment - Task // Complete - > - >; - using WebSocketAccept = - Action - < - IDictionary, // WebSocket Accept parameters - Func // WebSocketFunc callback - < - IDictionary, // WebSocket environment - Task // Complete - > - >; - using WebSocketFunc = - Func - < - IDictionary, // WebSocket Environment - Task // Complete - >; - - public class WebSocketMiddleware - { - private AppFunc _next; - - public WebSocketMiddleware(AppFunc next) - { - _next = next; - } - - public Task Invoke(IDictionary environment) - { - IOwinContext context = new OwinContext(environment); - // Detect if an opaque upgrade is available, and if websocket upgrade headers are present. - // If so, add a websocket upgrade. - OpaqueUpgrade upgrade = context.Get("opaque.Upgrade"); - if (upgrade != null) - { - // Headers and values: - // Connection: Upgrade - // Upgrade: WebSocket - // Sec-WebSocket-Version: (WebSocketProtocolComponent.SupportedVersion) - // Sec-WebSocket-Key: (hash, see WebSocketHelpers.GetSecWebSocketAcceptString) - // Sec-WebSocket-Protocol: (optional, list) - IList connectionHeaders = context.Request.Headers.GetCommaSeparatedValues(HttpKnownHeaderNames.Connection); // "Upgrade, KeepAlive" - string upgradeHeader = context.Request.Headers[HttpKnownHeaderNames.Upgrade]; - string versionHeader = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - string keyHeader = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - - if (connectionHeaders != null && connectionHeaders.Count > 0 - && connectionHeaders.Contains(HttpKnownHeaderNames.Upgrade, StringComparer.OrdinalIgnoreCase) - && string.Equals(upgradeHeader, WebSocketHelpers.WebSocketUpgradeToken, StringComparison.OrdinalIgnoreCase) - && string.Equals(versionHeader, UnsafeNativeMethods.WebSocketProtocolComponent.SupportedVersion, StringComparison.OrdinalIgnoreCase) - && !string.IsNullOrWhiteSpace(keyHeader)) - { - environment["websocket.Accept"] = new WebSocketAccept(new UpgradeHandshake(context, upgrade).AcceptWebSocket); - } - } - - return _next(environment); - } - - private class UpgradeHandshake - { - private IOwinContext _context; - private OpaqueUpgrade _upgrade; - private WebSocketFunc _webSocketFunc; - - private string _subProtocol; - private int _receiveBufferSize = WebSocketHelpers.DefaultReceiveBufferSize; - private TimeSpan _keepAliveInterval = WebSocket.DefaultKeepAliveInterval; - private ArraySegment _internalBuffer; - - internal UpgradeHandshake(IOwinContext context, OpaqueUpgrade upgrade) - { - _context = context; - _upgrade = upgrade; - } - - internal void AcceptWebSocket(IDictionary options, WebSocketFunc webSocketFunc) - { - _webSocketFunc = webSocketFunc; - - // Get options - object temp; - if (options != null && options.TryGetValue("websocket.SubProtocol", out temp)) - { - _subProtocol = temp as string; - } - if (options != null && options.TryGetValue("websocket.ReceiveBufferSize", out temp)) - { - _receiveBufferSize = (int)temp; - } - if (options != null && options.TryGetValue("websocket.KeepAliveInterval", out temp)) - { - _keepAliveInterval = (TimeSpan)temp; - } - if (options != null && options.TryGetValue("websocket.Buffer", out temp)) - { - _internalBuffer = (ArraySegment)temp; - } - else - { - _internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(_receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - } - - // Set WebSocket upgrade response headers - - string outgoingSecWebSocketProtocolString; - bool shouldSendSecWebSocketProtocolHeader = - WebSocketHelpers.ProcessWebSocketProtocolHeader( - _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol], - _subProtocol, - out outgoingSecWebSocketProtocolString); - - if (shouldSendSecWebSocketProtocolHeader) - { - _context.Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = outgoingSecWebSocketProtocolString; - } - - string secWebSocketKey = _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); - - _context.Response.Headers[HttpKnownHeaderNames.Connection] = HttpKnownHeaderNames.Upgrade; - _context.Response.Headers[HttpKnownHeaderNames.Upgrade] = WebSocketHelpers.WebSocketUpgradeToken; - _context.Response.Headers[HttpKnownHeaderNames.SecWebSocketAccept] = secWebSocketAccept; - - _context.Response.StatusCode = 101; // Switching Protocols; - - _upgrade(options, OpaqueCallback); - } - - internal async Task OpaqueCallback(IDictionary opaqueEnv) - { - // Create WebSocket wrapper around the opaque env - WebSocket webSocket = CreateWebSocket(opaqueEnv); - OwinWebSocketWrapper wrapper = new OwinWebSocketWrapper(webSocket, (CancellationToken)opaqueEnv["opaque.CallCancelled"]); - await _webSocketFunc(wrapper.Environment); - // Close down the WebSocekt, gracefully if possible - await wrapper.CleanupAsync(); - } - - private WebSocket CreateWebSocket(IDictionary opaqueEnv) - { - Stream stream = (Stream)opaqueEnv["opaque.Stream"]; - return new ServerWebSocket(stream, _subProtocol, _receiveBufferSize, _keepAliveInterval, _internalBuffer); - } - } - } -} -*/ \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs b/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs deleted file mode 100644 index 7513597105..0000000000 --- a/src/Microsoft.AspNet.WebSockets/WebSocketReceiveResult.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics.Contracts; - -namespace Microsoft.AspNet.WebSockets -{ - public class WebSocketReceiveResult - { - public WebSocketReceiveResult(int count, WebSocketMessageType messageType, bool endOfMessage) - : this(count, messageType, endOfMessage, null, null) - { - } - - public WebSocketReceiveResult(int count, - WebSocketMessageType messageType, - bool endOfMessage, - WebSocketCloseStatus? closeStatus, - string closeStatusDescription) - { - if (count < 0) - { - throw new ArgumentOutOfRangeException("count"); - } - - this.Count = count; - this.EndOfMessage = endOfMessage; - this.MessageType = messageType; - this.CloseStatus = closeStatus; - this.CloseStatusDescription = closeStatusDescription; - } - - public int Count { get; private set; } - public bool EndOfMessage { get; private set; } - public WebSocketMessageType MessageType { get; private set; } - public WebSocketCloseStatus? CloseStatus { get; private set; } - public string CloseStatusDescription { get; private set; } - - internal WebSocketReceiveResult Copy(int count) - { - Contract.Assert(count >= 0, "'count' MUST NOT be negative."); - Contract.Assert(count <= this.Count, "'count' MUST NOT be bigger than 'this.Count'."); - this.Count -= count; - return new WebSocketReceiveResult(count, - this.MessageType, - this.Count == 0 && this.EndOfMessage, - this.CloseStatus, - this.CloseStatusDescription); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketState.cs b/src/Microsoft.AspNet.WebSockets/WebSocketState.cs deleted file mode 100644 index 53d8d2daa5..0000000000 --- a/src/Microsoft.AspNet.WebSockets/WebSocketState.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.AspNet.WebSockets -{ - public enum WebSocketState - { - None = 0, - Connecting = 1, - Open = 2, - CloseSent = 3, // WebSocket close handshake started form local endpoint - CloseReceived = 4, // WebSocket close message received from remote endpoint. Waiting for app to call close - Closed = 5, - Aborted = 6, - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/project.json b/src/Microsoft.AspNet.WebSockets/project.json deleted file mode 100644 index da531b3e9e..0000000000 --- a/src/Microsoft.AspNet.WebSockets/project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "version": "0.1-alpha-*", - "dependencies": { - "Microsoft.AspNet.Http" : "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*" - }, - "compilationOptions" : { "allowUnsafe": true }, - "configurations": { - "net45" : { - "dependencies": { - } - } - } -} diff --git a/src/Microsoft.Net.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Server/RequestProcessing/Request.cs index 934c4e7728..2b3f4f1262 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Request.cs @@ -441,6 +441,17 @@ namespace Microsoft.Net.Server return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress); } + // TODO: We need an easier to user header collection that has this built in + internal string GetHeader(string headerName) + { + string[] values; + if (Headers.TryGetValue(headerName, out values)) + { + return string.Join(", ", values); + } + return string.Empty; + } + // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to // enable this, but it's unclear what Http.Sys would do. diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index ca09228b6d..ad3d7fc7e8 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -24,23 +24,24 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Net.WebSockets; using System.Runtime.InteropServices; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.Framework.Logging; +using Microsoft.Net.WebSockets; namespace Microsoft.Net.Server { - using OpaqueFunc = Func, Task>; - public sealed class RequestContext : IDisposable { private WebListener _server; private Request _request; private Response _response; private NativeRequestContext _memoryBlob; - private OpaqueFunc _opaqueCallback; private bool _disposed; private CancellationTokenSource _requestAbortSource; private CancellationToken? _disconnectToken; @@ -128,17 +129,230 @@ namespace Microsoft.Net.Server return Request.RequestId; } } - /* - public bool TryGetOpaqueUpgrade(ref Action, OpaqueFunc> value) + + public bool IsUpgradableRequest { - if (_request.IsUpgradable) - { - value = OpaqueUpgrade; - return true; - } - return false; + get { return _request.IsUpgradable; } } + public Task UpgradeAsync() + { + if (!IsUpgradableRequest || _response.SentHeaders) + { + throw new InvalidOperationException(); + } + + // Set the status code and reason phrase + Response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; + Response.ReasonPhrase = HttpReasonPhrase.Get(HttpStatusCode.SwitchingProtocols); + + Response.SendOpaqueUpgrade(); // TODO: Async + Request.SwitchToOpaqueMode(); + Response.SwitchToOpaqueMode(); + Stream opaqueStream = new OpaqueStream(Request.Body, Response.Body); + return Task.FromResult(opaqueStream); + } + + public bool IsWebSocketRequest + { + get + { + if (!WebSocketHelpers.AreWebSocketsSupported) + { + return false; + } + + if (!IsUpgradableRequest) + { + return false; + } + + if (!string.Equals("GET", Request.Method, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) + string connection = Request.GetHeader(HttpKnownHeaderNames.Connection); + if (connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) + { + return false; + } + + // Upgrade: websocket + string upgrade = Request.GetHeader(HttpKnownHeaderNames.Upgrade); + if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // Sec-WebSocket-Version: 13 + string version = Request.GetHeader(HttpKnownHeaderNames.SecWebSocketVersion); + if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // Sec-WebSocket-Key: {base64string} + string key = Request.GetHeader(HttpKnownHeaderNames.SecWebSocketKey); + if (!WebSocketHelpers.IsValidWebSocketKey(key)) + { + return false; + } + + return true; + } + } + + // Compare IsWebSocketRequest + private void ValidateWebSocketRequest() + { + if (!WebSocketHelpers.AreWebSocketsSupported) + { + throw new NotSupportedException("WebSockets are not supported on this platform."); + } + + if (!IsUpgradableRequest) + { + throw new InvalidOperationException("This request is not a valid upgrade request."); + } + + if (!string.Equals("GET", Request.Method, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("This request is not a valid upgrade request; invalid verb: " + Request.Method); + } + + // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) + string connection = Request.GetHeader(HttpKnownHeaderNames.Connection); + if (connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) + { + throw new InvalidOperationException("The Connection header is invalid: " + connection); + } + + // Upgrade: websocket + string upgrade = Request.GetHeader(HttpKnownHeaderNames.Upgrade); + if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The Upgrade header is invalid: " + upgrade); + } + + // Sec-WebSocket-Version: 13 + string version = Request.GetHeader(HttpKnownHeaderNames.SecWebSocketVersion); + if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The Sec-WebSocket-Version header is invalid or not supported: " + version); + } + + // Sec-WebSocket-Key: {base64string} + string key = Request.GetHeader(HttpKnownHeaderNames.SecWebSocketKey); + if (!WebSocketHelpers.IsValidWebSocketKey(key)) + { + throw new InvalidOperationException("The Sec-WebSocket-Key header is invalid: " + upgrade); + } + } + + public Task AcceptWebSocketAsync() + { + return AcceptWebSocketAsync(null, + WebSocketHelpers.DefaultReceiveBufferSize, + WebSocket.DefaultKeepAliveInterval); + } + + public Task AcceptWebSocketAsync(string subProtocol) + { + return AcceptWebSocketAsync(subProtocol, + WebSocketHelpers.DefaultReceiveBufferSize, + WebSocket.DefaultKeepAliveInterval); + } + + public Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval) + { + return AcceptWebSocketAsync(subProtocol, + WebSocketHelpers.DefaultReceiveBufferSize, + keepAliveInterval); + } + + public Task AcceptWebSocketAsync( + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval) + { + WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); + + ArraySegment internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + return this.AcceptWebSocketAsync(subProtocol, + receiveBufferSize, + keepAliveInterval, + internalBuffer); + } + + public Task AcceptWebSocketAsync( + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + { + if (!IsUpgradableRequest) + { + throw new InvalidOperationException("This request is cannot be upgraded."); + } + WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); + WebSocketHelpers.ValidateArraySegment(internalBuffer, "internalBuffer"); + WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + + return AcceptWebSocketAsyncCore(subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer); + } + + private async Task AcceptWebSocketAsyncCore( + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + { + try + { + // TODO: We need a better header collection API. + ValidateWebSocketRequest(); + + string subProtocols = string.Empty; + string[] values; + if (Request.Headers.TryGetValue(HttpKnownHeaderNames.SecWebSocketProtocol, out values)) + { + subProtocols = string.Join(", ", values); + } + + bool shouldSendSecWebSocketProtocolHeader = WebSocketHelpers.ProcessWebSocketProtocolHeader(subProtocols, subProtocol); + if (shouldSendSecWebSocketProtocolHeader) + { + Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = new[] { subProtocol }; + } + + // negotiate the websocket key return value + string secWebSocketKey = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey].First(); + string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); + + Response.Headers.Add(HttpKnownHeaderNames.Connection, new[] { HttpKnownHeaderNames.Upgrade }); + Response.Headers.Add(HttpKnownHeaderNames.Upgrade, new[] { WebSocketHelpers.WebSocketUpgradeToken }); + Response.Headers.Add(HttpKnownHeaderNames.SecWebSocketAccept, new[] { secWebSocketAccept }); + + Stream opaqueStream = await UpgradeAsync(); + + return WebSocketHelpers.CreateServerWebSocket( + opaqueStream, + subProtocol, + receiveBufferSize, + keepAliveInterval, + internalBuffer); + } + catch (Exception ex) + { + LogHelper.LogException(Logger, "AcceptWebSocketAsync", ex); + throw; + } + } + + + /* public bool TryGetChannelBinding(ref ChannelBinding value) { value = Server.GetChannelBinding(Request.ConnectionId, Request.IsSecureConnection); @@ -221,57 +435,5 @@ namespace Microsoft.Net.Server // RequestQueueHandle may have been closed } } - /* - internal void OpaqueUpgrade(IDictionary parameters, OpaqueFunc callback) - { - // Parameters are ignored for now - if (Response.SentHeaders) - { - throw new InvalidOperationException(); - } - if (callback == null) - { - throw new ArgumentNullException("callback"); - } - - // Set the status code and reason phrase - Response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; - Response.ReasonPhrase = HttpReasonPhrase.Get(HttpStatusCode.SwitchingProtocols); - - // Store the callback and process it after the stack unwind. - _opaqueCallback = callback; - } - - // Called after the AppFunc completes for any necessary post-processing. - internal unsafe Task ProcessResponseAsync() - { - // If an upgrade was requested, perform it - if (!Response.SentHeaders && _opaqueCallback != null - && Response.StatusCode == (int)HttpStatusCode.SwitchingProtocols) - { - Response.SendOpaqueUpgrade(); - - IDictionary opaqueEnv = CreateOpaqueEnvironment(); - return _opaqueCallback(opaqueEnv); - } - - return Helpers.CompletedTask(); - } - - private IDictionary CreateOpaqueEnvironment() - { - IDictionary opaqueEnv = new Dictionary(); - - opaqueEnv[Constants.OpaqueVersionKey] = Constants.OpaqueVersion; - // TODO: Separate CT? - // opaqueEnv[Constants.OpaqueCallCancelledKey] = Environment.CallCancelled; - - Request.SwitchToOpaqueMode(); - Response.SwitchToOpaqueMode(); - opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.Body, Response.Body); - - return opaqueEnv; - } - */ } } diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Server/project.json index a6363b7940..0316ca03aa 100644 --- a/src/Microsoft.Net.Server/project.json +++ b/src/Microsoft.Net.Server/project.json @@ -1,7 +1,8 @@ { "version": "0.1-alpha-*", "dependencies": { - "Microsoft.Framework.Logging": "0.1-alpha-*" + "Microsoft.Framework.Logging": "0.1-alpha-*", + "Microsoft.Net.WebSockets": "" }, "compilationOptions": { "allowUnsafe": true @@ -10,6 +11,7 @@ "net45": {}, "k10": { "dependencies": { + "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*", "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.0.0", "System.Collections.Concurrent": "4.0.0.0", diff --git a/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs b/src/Microsoft.Net.WebSockets/HttpKnownHeaderNames.cs similarity index 99% rename from src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs rename to src/Microsoft.Net.WebSockets/HttpKnownHeaderNames.cs index 3382395c8b..fb6fa1d755 100644 --- a/src/Microsoft.AspNet.WebSockets/HttpKnownHeaderNames.cs +++ b/src/Microsoft.Net.WebSockets/HttpKnownHeaderNames.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { // this class contains known header names internal static class HttpKnownHeaderNames diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/SR.cs b/src/Microsoft.Net.WebSockets/Legacy/SR.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/Legacy/SR.cs rename to src/Microsoft.Net.WebSockets/Legacy/SR.cs diff --git a/src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs b/src/Microsoft.Net.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs rename to src/Microsoft.Net.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs diff --git a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj similarity index 83% rename from src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj rename to src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj index fb4bf3edd4..031b4e912b 100644 --- a/src/Microsoft.AspNet.WebSockets/Microsoft.AspNet.WebSockets.kproj +++ b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj @@ -22,7 +22,6 @@ - @@ -31,29 +30,21 @@ - - - - - + - - - - + - - + \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.Net.WebSockets/NativeInterop/SafeLoadLibrary.cs similarity index 98% rename from src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs rename to src/Microsoft.Net.WebSockets/NativeInterop/SafeLoadLibrary.cs index 6b0e6e2ee2..dcb231e78b 100644 --- a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeLoadLibrary.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/SafeLoadLibrary.cs @@ -23,7 +23,7 @@ using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs similarity index 98% rename from src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs rename to src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs index 7e404fb597..2bbf1c58bf 100644 --- a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs @@ -25,7 +25,7 @@ using System; using System.Runtime.InteropServices; using System.Threading; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { internal class SafeNativeOverlapped : SafeHandle { diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs b/src/Microsoft.Net.WebSockets/NativeInterop/SafeWebSocketHandle.cs similarity index 96% rename from src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs rename to src/Microsoft.Net.WebSockets/NativeInterop/SafeWebSocketHandle.cs index fffd04af4f..1219624f00 100644 --- a/src/Microsoft.AspNet.WebSockets/NativeInterop/SafeWebSocketHandle.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/SafeWebSocketHandle.cs @@ -21,10 +21,9 @@ // //------------------------------------------------------------------------------ -using Microsoft.AspNet.WebSockets; using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { // This class is a wrapper for a WSPC (WebSocket protocol component) session. WebSocketCreateClientHandle and WebSocketCreateServerHandle return a PVOID and not a real handle // but we use a SafeHandle because it provides us the guarantee that WebSocketDeleteHandle will always get called. diff --git a/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs similarity index 99% rename from src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs rename to src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs index d9875f0afc..c2002b7f22 100644 --- a/src/Microsoft.AspNet.WebSockets/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -27,7 +27,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { internal static class UnsafeNativeMethods { @@ -161,7 +161,11 @@ namespace Microsoft.AspNet.WebSockets static WebSocketProtocolComponent() { +#if NET45 DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); +#else + DllFileName = Path.Combine(Environment.GetEnvironmentVariable("SYSTEMROOT"), "System32", WEBSOCKET); +#endif WebSocketDllHandle = SafeLoadLibrary.LoadLibraryEx(DllFileName); if (!WebSocketDllHandle.IsInvalid) diff --git a/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs b/src/Microsoft.Net.WebSockets/ServerWebSocket.cs similarity index 98% rename from src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs rename to src/Microsoft.Net.WebSockets/ServerWebSocket.cs index b722573934..ebf8542848 100644 --- a/src/Microsoft.AspNet.WebSockets/ServerWebSocket.cs +++ b/src/Microsoft.Net.WebSockets/ServerWebSocket.cs @@ -27,7 +27,7 @@ using System.Diagnostics.Contracts; using System.IO; using System.Runtime.InteropServices; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { internal sealed class ServerWebSocket : WebSocketBase { diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs b/src/Microsoft.Net.WebSockets/WebSocketBase.cs similarity index 98% rename from src/Microsoft.AspNet.WebSockets/WebSocketBase.cs rename to src/Microsoft.Net.WebSockets/WebSocketBase.cs index 66e5aa4760..fe2ab6d1e2 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketBase.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBase.cs @@ -29,13 +29,14 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.IO; +using System.Net.WebSockets; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { internal abstract class WebSocketBase : WebSocket, IDisposable { @@ -233,7 +234,7 @@ namespace Microsoft.AspNet.WebSockets { ThrowIfPendingException(); ThrowIfDisposed(); - ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseSent); + WebSocketHelpers.ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseSent); bool ownsCancellationTokenSource = false; CancellationToken linkedCancellationToken = CancellationToken.None; @@ -338,7 +339,7 @@ namespace Microsoft.AspNet.WebSockets { ThrowIfPendingException(); ThrowIfDisposed(); - ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived); + WebSocketHelpers.ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived); bool ownsCancellationTokenSource = false; CancellationToken linkedCancellationToken = CancellationToken.None; @@ -468,13 +469,13 @@ namespace Microsoft.AspNet.WebSockets bool sessionHandleLockTaken = false; try { - if (IsStateTerminal(State)) + if (WebSocketHelpers.IsStateTerminal(State)) { return; } TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - if (IsStateTerminal(State)) + if (WebSocketHelpers.IsStateTerminal(State)) { return; } @@ -548,7 +549,7 @@ namespace Microsoft.AspNet.WebSockets try { ThrowIfPendingException(); - if (IsStateTerminal(State)) + if (WebSocketHelpers.IsStateTerminal(State)) { return; } @@ -566,12 +567,12 @@ namespace Microsoft.AspNet.WebSockets ThrowIfPendingException(); ThrowIfDisposed(); - if (IsStateTerminal(State)) + if (WebSocketHelpers.IsStateTerminal(State)) { return; } - ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived); + WebSocketHelpers.ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived); ownsCloseOutputCancellationTokenSource = _closeOutputOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); if (!ownsCloseOutputCancellationTokenSource) { @@ -676,7 +677,7 @@ namespace Microsoft.AspNet.WebSockets // returns TRUE if the caller should also call StartOnCloseCompleted private bool OnCloseOutputCompleted() { - if (IsStateTerminal(State)) + if (WebSocketHelpers.IsStateTerminal(State)) { return false; } @@ -707,7 +708,7 @@ namespace Microsoft.AspNet.WebSockets { Contract.Assert(thisLockTakenSnapshot, "'thisLockTakenSnapshot' MUST be 'true' at this point."); - if (IsStateTerminal(_state)) + if (WebSocketHelpers.IsStateTerminal(_state)) { return false; } @@ -793,7 +794,7 @@ namespace Microsoft.AspNet.WebSockets try { ThrowIfPendingException(); - if (IsStateTerminal(State)) + if (WebSocketHelpers.IsStateTerminal(State)) { return; } @@ -806,12 +807,12 @@ namespace Microsoft.AspNet.WebSockets try { ThrowIfPendingException(); - if (IsStateTerminal(State)) + if (WebSocketHelpers.IsStateTerminal(State)) { return; } ThrowIfDisposed(); - ThrowOnInvalidState(State, + WebSocketHelpers.ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived, WebSocketState.CloseSent); Task closeOutputTask; @@ -893,7 +894,7 @@ namespace Microsoft.AspNet.WebSockets } } - if (IsStateTerminal(State)) + if (WebSocketHelpers.IsStateTerminal(State)) { return; } @@ -970,7 +971,7 @@ namespace Microsoft.AspNet.WebSockets Monitor.Enter(_thisLock, ref lockTaken); } - if (!IsStateTerminal(State)) + if (!WebSocketHelpers.IsStateTerminal(State)) { bool ownsSendCancellationSource = false; try @@ -1055,7 +1056,7 @@ namespace Microsoft.AspNet.WebSockets return; } - if (!IsStateTerminal(State)) + if (!WebSocketHelpers.IsStateTerminal(State)) { Abort(); } @@ -1501,13 +1502,13 @@ namespace Microsoft.AspNet.WebSockets { ThrowIfDisposed(); - if (IsStateTerminal(State) || State == WebSocketState.CloseReceived) + if (WebSocketHelpers.IsStateTerminal(State) || State == WebSocketState.CloseReceived) { return false; } Monitor.Enter(_thisLock, ref thisLockTaken); - if (IsStateTerminal(State) || State == WebSocketState.CloseReceived) + if (WebSocketHelpers.IsStateTerminal(State) || State == WebSocketState.CloseReceived) { return false; } diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs similarity index 98% rename from src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs rename to src/Microsoft.Net.WebSockets/WebSocketBuffer.cs index 2f9522fd40..a34b458f7c 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketBuffer.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs @@ -25,11 +25,12 @@ using System; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Globalization; +using System.Net.WebSockets; using System.Runtime.InteropServices; using System.Text; using System.Threading; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { // This class helps to abstract the internal WebSocket buffer, which is used to interact with the native WebSocket // protocol component (WSPC). It helps to shield the details of the layout and the involved pointer arithmetic. @@ -43,10 +44,10 @@ namespace Microsoft.AspNet.WebSockets // // *RBS = ReceiveBufferSize, *SBS = SendBufferSize // *PBS = PropertyBufferSize (32-bit: 16, 64 bit: 20 bytes) - internal class WebSocketBuffer : IDisposable + public class WebSocketBuffer : IDisposable { private const int NativeOverheadBufferSize = 144; - internal const int MinSendBufferSize = 16; + public const int MinSendBufferSize = 16; internal const int MinReceiveBufferSize = 256; internal const int MaxBufferSize = 64 * 1024; #if NET45 @@ -362,7 +363,7 @@ namespace Microsoft.AspNet.WebSockets ValidateBufferedPayload(); int bytesTransferred = Math.Min(buffer.Count, _BufferedPayloadReceiveResult.Count); - receiveResult = _BufferedPayloadReceiveResult.Copy(bytesTransferred); + receiveResult = WebSocketReceiveResultExtensions.DecrementAndClone(ref _BufferedPayloadReceiveResult, bytesTransferred); Buffer.BlockCopy(_PayloadBuffer.Array, _PayloadBuffer.Offset + _PayloadOffset, @@ -664,7 +665,7 @@ namespace Microsoft.AspNet.WebSockets ReleasePinnedSendBuffer(); } - internal static ArraySegment CreateInternalBufferArraySegment(int receiveBufferSize, int sendBufferSize, bool isServerBuffer) + public static ArraySegment CreateInternalBufferArraySegment(int receiveBufferSize, int sendBufferSize, bool isServerBuffer) { Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); @@ -675,7 +676,7 @@ namespace Microsoft.AspNet.WebSockets return new ArraySegment(new byte[internalBufferSize]); } - internal static void Validate(int count, int receiveBufferSize, int sendBufferSize, bool isServerBuffer) + public static void Validate(int count, int receiveBufferSize, int sendBufferSize, bool isServerBuffer) { Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); diff --git a/src/Microsoft.Net.WebSockets/WebSocketConstants.cs b/src/Microsoft.Net.WebSockets/WebSocketConstants.cs new file mode 100644 index 0000000000..c5aa4d8a85 --- /dev/null +++ b/src/Microsoft.Net.WebSockets/WebSocketConstants.cs @@ -0,0 +1,9 @@ +using System; + +namespace Microsoft.Net.WebSockets +{ + public static class WebSocketConstants + { + public static string SupportedProtocolVersion = "13"; + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketError.cs b/src/Microsoft.Net.WebSockets/WebSocketError.cs similarity index 97% rename from src/Microsoft.AspNet.WebSockets/WebSocketError.cs rename to src/Microsoft.Net.WebSockets/WebSocketError.cs index 16ce90e9fd..11c84c27a5 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketError.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketError.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { public enum WebSocketError { diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketException.cs b/src/Microsoft.Net.WebSockets/WebSocketException.cs similarity index 99% rename from src/Microsoft.AspNet.WebSockets/WebSocketException.cs rename to src/Microsoft.Net.WebSockets/WebSocketException.cs index b1691a1e1b..1e923616ad 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketException.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketException.cs @@ -23,9 +23,10 @@ using System; using System.ComponentModel; +using System.Net.WebSockets; using System.Runtime.InteropServices; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { #if NET45 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] diff --git a/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs b/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs similarity index 58% rename from src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs rename to src/Microsoft.Net.WebSockets/WebSocketHelpers.cs index 331f007ed6..7d61cff7a1 100644 --- a/src/Microsoft.AspNet.WebSockets/WebSocketHelpers.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs @@ -26,21 +26,20 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.IO; +using System.Net.WebSockets; using System.Runtime.CompilerServices; -#if NET45 using System.Security.Cryptography; -#endif using System.Text; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.Net.WebSockets { - internal static class WebSocketHelpers + public static class WebSocketHelpers { internal const string SecWebSocketKeyGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - internal const string WebSocketUpgradeToken = "websocket"; - internal const int DefaultReceiveBufferSize = 16 * 1024; + public const string WebSocketUpgradeToken = "websocket"; + public const int DefaultReceiveBufferSize = 16 * 1024; internal const int DefaultClientSendBufferSize = 16 * 1024; internal const int MaxControlFramePayloadLength = 123; @@ -63,138 +62,30 @@ namespace Microsoft.AspNet.WebSockets internal static readonly ArraySegment EmptyPayload = new ArraySegment(new byte[] { }, 0, 0); private static readonly Random KeyGenerator = new Random(); -/* - internal static Task AcceptWebSocketAsync(HttpListenerContext context, - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) + public static bool AreWebSocketsSupported { - WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); - WebSocketHelpers.ValidateArraySegment(internalBuffer, "internalBuffer"); - WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - - return AcceptWebSocketAsyncCore(context, subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer); + get + { + return UnsafeNativeMethods.WebSocketProtocolComponent.IsSupported; + } } - - private static async Task AcceptWebSocketAsyncCore(HttpListenerContext context, - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) + + public static bool IsValidWebSocketKey(string key) { - HttpListenerWebSocketContext webSocketContext = null; - /*if (Logging.On) + if (string.IsNullOrWhiteSpace(key)) { - Logging.Enter(Logging.WebSockets, context, "AcceptWebSocketAsync", ""); - }* / - - try - { - // get property will create a new response if one doesn't exist. - HttpListenerResponse response = context.Response; - HttpListenerRequest request = context.Request; - ValidateWebSocketHeaders(context); - - string secWebSocketVersion = request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - - // Optional for non-browser client - string origin = request.Headers[HttpKnownHeaderNames.Origin]; - - List secWebSocketProtocols = new List(); - string outgoingSecWebSocketProtocolString; - bool shouldSendSecWebSocketProtocolHeader = - WebSocketHelpers.ProcessWebSocketProtocolHeader( - request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol], - subProtocol, - out outgoingSecWebSocketProtocolString); - - if (shouldSendSecWebSocketProtocolHeader) - { - secWebSocketProtocols.Add(outgoingSecWebSocketProtocolString); - response.Headers.Add(HttpKnownHeaderNames.SecWebSocketProtocol, - outgoingSecWebSocketProtocolString); - } - - // negotiate the websocket key return value - string secWebSocketKey = request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); - - response.Headers.Add(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); - response.Headers.Add(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); - response.Headers.Add(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); - - response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; // HTTP 101 - response.ComputeCoreHeaders(); - ulong hresult = SendWebSocketHeaders(response); - if (hresult != 0) - { - throw new WebSocketException((int)hresult, - SR.GetString(SR.net_WebSockets_NativeSendResponseHeaders, - WebSocketHelpers.MethodNames.AcceptWebSocketAsync, - hresult)); - } - - await response.OutputStream.FlushAsync().SuppressContextFlow(); // TODO:??? FlushAsync was never implemented - - HttpResponseStream responseStream = response.OutputStream as HttpResponseStream; - Contract.Assert(responseStream != null, "'responseStream' MUST be castable to System.Net.HttpResponseStream."); - ((HttpResponseStream)response.OutputStream).SwitchToOpaqueMode(); - HttpRequestStream requestStream = new HttpRequestStream(context); - requestStream.SwitchToOpaqueMode(); - WebSocketHttpListenerDuplexStream webSocketStream = - new WebSocketHttpListenerDuplexStream(requestStream, responseStream, context); - WebSocket webSocket = WebSocket.CreateServerWebSocket(webSocketStream, - subProtocol, - receiveBufferSize, - keepAliveInterval, - internalBuffer); - - webSocketContext = new HttpListenerWebSocketContext( - request.Url, - request.Headers, - request.Cookies, - context.User, - request.IsAuthenticated, - request.IsLocal, - request.IsSecureConnection, - origin, - secWebSocketProtocols.AsReadOnly(), - secWebSocketVersion, - secWebSocketKey, - webSocket); - - if (Logging.On) - { - Logging.Associate(Logging.WebSockets, context, webSocketContext); - Logging.Associate(Logging.WebSockets, webSocketContext, webSocket); - } + return false; } - catch (Exception ex) - { - if (Logging.On) - { - Logging.Exception(Logging.WebSockets, context, "AcceptWebSocketAsync", ex); - } - throw; - } - finally - { - if (Logging.On) - { - Logging.Exit(Logging.WebSockets, context, "AcceptWebSocketAsync", ""); - } - } - return webSocketContext; + // TODO: + // throw new NotImplementedException(); + return true; } - -*/ + [SuppressMessage("Microsoft.Cryptographic.Standard", "CA5354:SHA1CannotBeUsed", Justification = "SHA1 used only for hashing purposes, not for crypto.")] - internal static string GetSecWebSocketAcceptString(string secWebSocketKey) + public static string GetSecWebSocketAcceptString(string secWebSocketKey) { string retVal; -#if NET45 // SHA1 used only for hashing purposes, not for crypto. Check here for FIPS compat. using (SHA1 sha1 = SHA1.Create()) { @@ -202,10 +93,14 @@ namespace Microsoft.AspNet.WebSockets byte[] toHash = Encoding.UTF8.GetBytes(acceptString); retVal = Convert.ToBase64String(sha1.ComputeHash(toHash)); } -#endif return retVal; } + public static WebSocket CreateServerWebSocket(Stream opaqueStream, string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval, ArraySegment internalBuffer) + { + return new ServerWebSocket(opaqueStream, subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer); + } + internal static string GetTraceMsgForParameters(int offset, int count, CancellationToken cancellationToken) { return string.Format(CultureInfo.InvariantCulture, @@ -216,11 +111,8 @@ namespace Microsoft.AspNet.WebSockets } // return value here signifies if a Sec-WebSocket-Protocol header should be returned by the server. - internal static bool ProcessWebSocketProtocolHeader(string clientSecWebSocketProtocol, - string subProtocol, - out string acceptProtocol) + public static bool ProcessWebSocketProtocolHeader(string clientSecWebSocketProtocol, string subProtocol) { - acceptProtocol = string.Empty; if (string.IsNullOrEmpty(clientSecWebSocketProtocol)) { // client hasn't specified any Sec-WebSocket-Protocol header @@ -236,10 +128,10 @@ namespace Microsoft.AspNet.WebSockets // here, we know the client specified something and it's non-empty. - if (subProtocol == null) + if (string.IsNullOrEmpty(subProtocol)) { // client specified some protocols, server specified 'null'. So server should send headers. - return true; + return false; } // here, we know that the client has specified something, it's not empty @@ -247,14 +139,13 @@ namespace Microsoft.AspNet.WebSockets string[] requestProtocols = clientSecWebSocketProtocol.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - acceptProtocol = subProtocol; // client specified protocols, serverOptions has exactly 1 non-empty entry. Check that // this exists in the list the client specified. for (int i = 0; i < requestProtocols.Length; i++) { string currentRequestProtocol = requestProtocols[i].Trim(); - if (string.Compare(acceptProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase) == 0) + if (string.Compare(subProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase) == 0) { return true; } @@ -281,7 +172,34 @@ namespace Microsoft.AspNet.WebSockets // under the caller's synchronization context. return task.ConfigureAwait(false); } - + + internal static bool IsStateTerminal(WebSocketState state) + { + return state == WebSocketState.Closed || state == WebSocketState.Aborted; + } + + internal static void ThrowOnInvalidState(WebSocketState state, params WebSocketState[] validStates) + { + string text = string.Empty; + if (validStates != null && validStates.Length > 0) + { + for (int i = 0; i < validStates.Length; i++) + { + WebSocketState webSocketState = validStates[i]; + if (state == webSocketState) + { + return; + } + } + text = string.Join(", ", validStates); + } + throw new WebSocketException(SR.GetString("net_WebSockets_InvalidState", new object[] + { + state, + text + })); + } + internal static void ValidateBuffer(byte[] buffer, int offset, int count) { if (buffer == null) @@ -299,57 +217,6 @@ namespace Microsoft.AspNet.WebSockets throw new ArgumentOutOfRangeException("count"); } } - /* - private static unsafe ulong SendWebSocketHeaders(HttpListenerResponse response) - { - return response.SendHeaders(null, null, - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE | - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA | - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA, - true); - } - private static void ValidateWebSocketHeaders(HttpListenerContext context) - { - EnsureHttpSysSupportsWebSockets(); - - if (!context.Request.IsWebSocketRequest) - { - throw new WebSocketException(WebSocketError.NotAWebSocket, - SR.GetString(SR.net_WebSockets_AcceptNotAWebSocket, - WebSocketHelpers.MethodNames.ValidateWebSocketHeaders, - HttpKnownHeaderNames.Connection, - HttpKnownHeaderNames.Upgrade, - WebSocketHelpers.WebSocketUpgradeToken, - context.Request.Headers[HttpKnownHeaderNames.Upgrade])); - } - - string secWebSocketVersion = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - if (string.IsNullOrEmpty(secWebSocketVersion)) - { - throw new WebSocketException(WebSocketError.HeaderError, - SR.GetString(SR.net_WebSockets_AcceptHeaderNotFound, - WebSocketHelpers.MethodNames.ValidateWebSocketHeaders, - HttpKnownHeaderNames.SecWebSocketVersion)); - } - - if (string.Compare(secWebSocketVersion, WebSocketProtocolComponent.SupportedVersion, StringComparison.OrdinalIgnoreCase) != 0) - { - throw new WebSocketException(WebSocketError.UnsupportedVersion, - SR.GetString(SR.net_WebSockets_AcceptUnsupportedWebSocketVersion, - WebSocketHelpers.MethodNames.ValidateWebSocketHeaders, - secWebSocketVersion, - WebSocketProtocolComponent.SupportedVersion)); - } - - if (string.IsNullOrWhiteSpace(context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey])) - { - throw new WebSocketException(WebSocketError.HeaderError, - SR.GetString(SR.net_WebSockets_AcceptHeaderNotFound, - WebSocketHelpers.MethodNames.ValidateWebSocketHeaders, - HttpKnownHeaderNames.SecWebSocketKey)); - } - } - */ internal static void ValidateSubprotocol(string subProtocol) { @@ -425,7 +292,7 @@ namespace Microsoft.AspNet.WebSockets } } - internal static void ValidateOptions(string subProtocol, + public static void ValidateOptions(string subProtocol, int receiveBufferSize, int sendBufferSize, TimeSpan keepAliveInterval) @@ -511,7 +378,7 @@ namespace Microsoft.AspNet.WebSockets throw new PlatformNotSupportedException(SR.GetString(SR.net_WebSockets_UnsupportedPlatform)); } - internal static void ValidateArraySegment(ArraySegment arraySegment, string parameterName) + public static void ValidateArraySegment(ArraySegment arraySegment, string parameterName) { Contract.Requires(!string.IsNullOrEmpty(parameterName), "'parameterName' MUST NOT be NULL or string.Empty"); @@ -529,11 +396,5 @@ namespace Microsoft.AspNet.WebSockets throw new ArgumentOutOfRangeException(parameterName + ".Count"); } } - - internal static class MethodNames - { - internal const string AcceptWebSocketAsync = "AcceptWebSocketAsync"; - internal const string ValidateWebSocketHeaders = "ValidateWebSocketHeaders"; - } } } diff --git a/src/Microsoft.Net.WebSockets/WebSocketMiddleware.cs b/src/Microsoft.Net.WebSockets/WebSocketMiddleware.cs new file mode 100644 index 0000000000..bac7e7cf32 --- /dev/null +++ b/src/Microsoft.Net.WebSockets/WebSocketMiddleware.cs @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. +/* TODO: +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.HttpFeature; +using Microsoft.Net.WebSockets; + +namespace Microsoft.AspNet.WebSockets +{ + public class WebSocketMiddleware + { + private RequestDelegate _next; + + public WebSocketMiddleware(RequestDelegate next) + { + _next = next; + } + + public Task Invoke(HttpContext context) + { + // Detect if an opaque upgrade is available, and if websocket upgrade headers are present. + // If so, add a websocket upgrade. + var upgradeFeature = context.GetFeature(); + if (upgradeFeature != null) + { + context.SetFeature(new UpgradeHandshake(context, upgradeFeature)); + } + + return _next(context); + } + + private class UpgradeHandshake : IHttpWebSocketFeature + { + private HttpContext _context; + private IHttpOpaqueUpgradeFeature _upgrade; + + private string _subProtocol; + private int _receiveBufferSize = WebSocketHelpers.DefaultReceiveBufferSize; + private TimeSpan _keepAliveInterval = WebSocket.DefaultKeepAliveInterval; + private ArraySegment? _internalBuffer; + + internal UpgradeHandshake(HttpContext context, IHttpOpaqueUpgradeFeature upgrade) + { + _context = context; + _upgrade = upgrade; + } + + public bool IsWebSocketRequest + { + get + { + // Headers and values: + // Connection: Upgrade + // Upgrade: WebSocket + // Sec-WebSocket-Version: (WebSocketProtocolComponent.SupportedVersion) + // Sec-WebSocket-Key: (hash, see WebSocketHelpers.GetSecWebSocketAcceptString) + // Sec-WebSocket-Protocol: (optional, list) + IList connectionHeaders = _context.Request.Headers.GetCommaSeparatedValues(HttpKnownHeaderNames.Connection); // "Upgrade, KeepAlive" + string upgradeHeader = _context.Request.Headers[HttpKnownHeaderNames.Upgrade]; + string versionHeader = _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; + string keyHeader = _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + + if (connectionHeaders != null && connectionHeaders.Count > 0 + && connectionHeaders.Contains(HttpKnownHeaderNames.Upgrade, StringComparer.OrdinalIgnoreCase) + && string.Equals(upgradeHeader, WebSocketHelpers.WebSocketUpgradeToken, StringComparison.OrdinalIgnoreCase) + && string.Equals(versionHeader, UnsafeNativeMethods.WebSocketProtocolComponent.SupportedVersion, StringComparison.OrdinalIgnoreCase) + && !string.IsNullOrWhiteSpace(keyHeader)) + { + return true; + } + return false; + } + } + + public async Task AcceptAsync(IWebSocketAcceptContext acceptContext) + { + // Get options + if (acceptContext != null) + { + _subProtocol = acceptContext.SubProtocol; + } + + var advancedAcceptContext = acceptContext as WebSocketAcceptContext; + if (advancedAcceptContext != null) + { + if (advancedAcceptContext.ReceiveBufferSize.HasValue) + { + _receiveBufferSize = advancedAcceptContext.ReceiveBufferSize.Value; + } + if (advancedAcceptContext.KeepAliveInterval.HasValue) + { + _keepAliveInterval = advancedAcceptContext.KeepAliveInterval.Value; + } + _internalBuffer = advancedAcceptContext.Buffer; + } + + if (!_internalBuffer.HasValue) + { + _internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(_receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + } + + // Set WebSocket upgrade response headers + + string outgoingSecWebSocketProtocolString; + bool shouldSendSecWebSocketProtocolHeader = + WebSocketHelpers.ProcessWebSocketProtocolHeader( + _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol], + _subProtocol, + out outgoingSecWebSocketProtocolString); + + if (shouldSendSecWebSocketProtocolHeader) + { + _context.Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = outgoingSecWebSocketProtocolString; + } + + string secWebSocketKey = _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); + + _context.Response.Headers[HttpKnownHeaderNames.Connection] = HttpKnownHeaderNames.Upgrade; + _context.Response.Headers[HttpKnownHeaderNames.Upgrade] = WebSocketHelpers.WebSocketUpgradeToken; + _context.Response.Headers[HttpKnownHeaderNames.SecWebSocketAccept] = secWebSocketAccept; + + // 101 Switching Protocols; + Stream opaqueTransport = await _upgrade.UpgradeAsync(); + return new ServerWebSocket(opaqueTransport, _subProtocol, _receiveBufferSize, _keepAliveInterval, _internalBuffer.Value); + } + } + + public class WebSocketAcceptContext : IWebSocketAcceptContext + { + public string SubProtocol { get; set; } + public int? ReceiveBufferSize { get; set; } + public TimeSpan? KeepAliveInterval { get; set; } + public ArraySegment? Buffer { get; set; } + } + } +}*/ \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/WebSocketReceiveResultExtensions.cs b/src/Microsoft.Net.WebSockets/WebSocketReceiveResultExtensions.cs new file mode 100644 index 0000000000..00df192c38 --- /dev/null +++ b/src/Microsoft.Net.WebSockets/WebSocketReceiveResultExtensions.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.Contracts; +using System.Net.WebSockets; + +namespace Microsoft.Net.WebSockets +{ + public static class WebSocketReceiveResultExtensions + { + internal static WebSocketReceiveResult DecrementAndClone(ref WebSocketReceiveResult original, int count) + { + Contract.Assert(count >= 0, "'count' MUST NOT be negative."); + Contract.Assert(count <= original.Count, "'count' MUST NOT be bigger than 'this.Count'."); + int remaining = original.Count - count; + original = new WebSocketReceiveResult(remaining, + original.MessageType, + original.EndOfMessage, + original.CloseStatus, + original.CloseStatusDescription); + return new WebSocketReceiveResult(count, + original.MessageType, + remaining == 0 && original.EndOfMessage, + original.CloseStatus, + original.CloseStatusDescription); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.WebSockets/build.cmd b/src/Microsoft.Net.WebSockets/build.cmd similarity index 100% rename from src/Microsoft.AspNet.WebSockets/build.cmd rename to src/Microsoft.Net.WebSockets/build.cmd diff --git a/src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs rename to src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/fx/System/AccessViolationException.cs rename to src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/fx/System/ComponentModel/Win32Exception.cs rename to src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/fx/System/ExternDll.cs rename to src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs rename to src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/fx/System/SafeNativeMethods.cs rename to src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs diff --git a/src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs similarity index 100% rename from src/Microsoft.AspNet.WebSockets/fx/System/SystemException.cs rename to src/Microsoft.Net.WebSockets/fx/System/SystemException.cs diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json new file mode 100644 index 0000000000..c3b93c599f --- /dev/null +++ b/src/Microsoft.Net.WebSockets/project.json @@ -0,0 +1,39 @@ +{ + "version": "0.1-alpha-*", + "dependencies": { + }, + "compilationOptions" : { "allowUnsafe": true }, + "configurations": { + "net45" : { }, + "k10" : { + "dependencies": { + "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*", + "Microsoft.Win32.Primitives": "4.0.0.0", + "System.Collections": "4.0.0.0", + "System.Collections.Concurrent": "4.0.0.0", + "System.Diagnostics.Contracts": "4.0.0.0", + "System.Diagnostics.Debug": "4.0.10.0", + "System.Diagnostics.Tools": "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO": "4.0.0.0", + "System.Linq": "4.0.0.0", + "System.Net.Primitives": "4.0.10.0", + "System.Reflection": "4.0.10.0", + "System.Resources.ResourceManager": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "System.Runtime.Extensions": "4.0.10.0", + "System.Runtime.Handles": "4.0.0.0", + "System.Runtime.InteropServices": "4.0.20.0", + "System.Security.Cryptography.HashAlgorithms.SHA1": "4.0.0.0", + "System.Security.Principal": "4.0.0.0", + "System.Text.Encoding": "4.0.20.0", + "System.Text.Encoding.Extensions": "4.0.10.0", + "System.Threading": "4.0.0.0", + "System.Threading.Overlapped": "4.0.0.0", + "System.Threading.Tasks": "4.0.10.0", + "System.Threading.Timer": "4.0.0.0", + "System.Threading.ThreadPool": "4.0.10.0" + } + } + } +} From 6a810fd6488bd4e5ca9718cc8ca02dbbc74c0b1a Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 16 Jun 2014 17:02:01 -0700 Subject: [PATCH 064/597] Add opaque upgrade tests. --- .../OpaqueUpgradeTests.cs | 161 ++++--------- .../OpaqueUpgradeTests.cs | 224 +++++------------- 2 files changed, 108 insertions(+), 277 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 3040ddeebc..6a72bffb2c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -15,7 +15,6 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -/* TODO: Opaque using System; using System.Collections.Generic; using System.IO; @@ -24,14 +23,13 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.PipelineCore; using Xunit; -using Xunit.Extensions; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - using OpaqueUpgrade = Action, Func, Task>>; - public class OpaqueUpgradeTests { private const string Address = "http://localhost:8080/"; @@ -39,22 +37,17 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task OpaqueUpgrade_SupportKeys_Present() { - using (CreateServer(env => + using (Utilities.CreateHttpServer(env => { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - IDictionary capabilities = env.Get>("server.Capabilities"); - Assert.NotNull(capabilities); - - Assert.Equal("1.0", capabilities.Get("opaque.Version")); - - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - Assert.NotNull(opaqueUpgrade); + var opaqueFeature = httpContext.GetFeature(); + Assert.NotNull(opaqueFeature); } catch (Exception ex) { - byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); + return httpContext.Response.WriteAsync(ex.ToString()); } return Task.FromResult(0); })) @@ -67,50 +60,25 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Fact] - public async Task OpaqueUpgrade_NullCallback_Throws() - { - using (CreateServer(env => - { - try - { - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - opaqueUpgrade(new Dictionary(), null); - } - catch (Exception ex) - { - byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); - } - return Task.FromResult(0); - })) - { - HttpResponseMessage response = await SendRequestAsync(Address); - Assert.Equal(200, (int)response.StatusCode); - Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); - Assert.Contains("callback", response.Content.ReadAsStringAsync().Result); - } - } - [Fact] public async Task OpaqueUpgrade_AfterHeadersSent_Throws() { bool? upgradeThrew = null; - using (CreateServer(env => + using (Utilities.CreateHttpServer(async env => { - byte[] body = Encoding.UTF8.GetBytes("Hello World"); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + await httpContext.Response.WriteAsync("Hello World"); try { - opaqueUpgrade(null, _ => Task.FromResult(0)); + var opaqueFeature = httpContext.GetFeature(); + Assert.NotNull(opaqueFeature); + await opaqueFeature.UpgradeAsync(); upgradeThrew = false; } catch (InvalidOperationException) { upgradeThrew = true; } - return Task.FromResult(0); })) { HttpResponseMessage response = await SendRequestAsync(Address); @@ -124,26 +92,24 @@ namespace Microsoft.AspNet.Server.WebListener public async Task OpaqueUpgrade_GetUpgrade_Success() { ManualResetEvent waitHandle = new ManualResetEvent(false); - bool? callbackInvoked = null; - using (CreateServer(env => + bool? upgraded = null; + using (Utilities.CreateHttpServer(async env => { - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Upgrade"] = new string[] { "websocket" }; // Win8.1 blocks anything but WebSockets - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - opaqueUpgrade(null, opqEnv => - { - callbackInvoked = true; - waitHandle.Set(); - return Task.FromResult(0); - }); - return Task.FromResult(0); + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets + var opaqueFeature = httpContext.GetFeature(); + Assert.NotNull(opaqueFeature); + Assert.True(opaqueFeature.IsUpgradableRequest); + await opaqueFeature.UpgradeAsync(); + upgraded = true; + waitHandle.Set(); })) { using (Stream stream = await SendOpaqueRequestAsync("GET", Address)) { Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); - Assert.True(callbackInvoked.HasValue, "CallbackInvoked not set"); - Assert.True(callbackInvoked.Value, "Callback not invoked"); + Assert.True(upgraded.HasValue, "Upgraded not set"); + Assert.True(upgraded.Value, "Upgrade failed"); } } } @@ -173,21 +139,26 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData("PUT", "Content-Length: 0")] public async Task OpaqueUpgrade_VariousMethodsUpgradeSendAndReceive_Success(string method, string extraHeader) { - using (CreateServer(env => + using (Utilities.CreateHttpServer(async env => { - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Upgrade"] = new string[] { "WebSocket" }; // Win8.1 blocks anything but WebSockets - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - opaqueUpgrade(null, async opqEnv => + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + try { - Stream opaqueStream = opqEnv.Get("opaque.Stream"); + httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets + var opaqueFeature = httpContext.GetFeature(); + Assert.NotNull(opaqueFeature); + Assert.True(opaqueFeature.IsUpgradableRequest); + var opaqueStream = await opaqueFeature.UpgradeAsync(); byte[] buffer = new byte[100]; int read = await opaqueStream.ReadAsync(buffer, 0, buffer.Length); await opaqueStream.WriteAsync(buffer, 0, read); - }); - return Task.FromResult(0); + } + catch (Exception ex) + { + await httpContext.Response.WriteAsync(ex.ToString()); + } })) { using (Stream stream = await SendOpaqueRequestAsync(method, Address, extraHeader)) @@ -208,54 +179,27 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData("PUT", "Transfer-Encoding: chunked")] [InlineData("CUSTOMVERB", "Content-Length: 10")] [InlineData("CUSTOMVERB", "Transfer-Encoding: chunked")] - public void OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) + public async Task OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) { - OpaqueUpgrade opaqueUpgrade = null; - using (CreateServer(env => + using (Utilities.CreateHttpServer(async env => { - opaqueUpgrade = env.Get("opaque.Upgrade"); - if (opaqueUpgrade == null) + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + try { - throw new NotImplementedException(); + var opaqueFeature = httpContext.GetFeature(); + Assert.NotNull(opaqueFeature); + Assert.False(opaqueFeature.IsUpgradableRequest); + } + catch (Exception ex) + { + await httpContext.Response.WriteAsync(ex.ToString()); } - opaqueUpgrade(null, opqEnv => Task.FromResult(0)); - return Task.FromResult(0); })) { - Assert.Throws(() => - { - try - { - return SendOpaqueRequestAsync(method, Address, extraHeader).Result; - } - catch (AggregateException ag) - { - throw ag.GetBaseException(); - } - }); - Assert.Null(opaqueUpgrade); + await Assert.ThrowsAsync(async () => await SendOpaqueRequestAsync(method, Address, extraHeader)); } } - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - OwinServerFactory.Initialize(properties); - - return OwinServerFactory.Create(app, properties); - } - private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) @@ -333,5 +277,4 @@ namespace Microsoft.AspNet.Server.WebListener } } } -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs index 031aeeca3b..4b4d82bee6 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -1,135 +1,57 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. -/* TODO: Opaque using System; -using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Net.Sockets; using System.Text; -using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Extensions; namespace Microsoft.Net.Server { - using AppFunc = Func; - using OpaqueUpgrade = Action, Func, Task>>; - public class OpaqueUpgradeTests { private const string Address = "http://localhost:8080/"; - [Fact] - public async Task OpaqueUpgrade_SupportKeys_Present() - { - using (CreateServer(env => - { - try - { - IDictionary capabilities = env.Get>("server.Capabilities"); - Assert.NotNull(capabilities); - - Assert.Equal("1.0", capabilities.Get("opaque.Version")); - - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - Assert.NotNull(opaqueUpgrade); - } - catch (Exception ex) - { - byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); - } - return Task.FromResult(0); - })) - { - HttpResponseMessage response = await SendRequestAsync(Address); - Assert.Equal(200, (int)response.StatusCode); - Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); - Assert.Equal(0, response.Content.Headers.ContentLength); - Assert.Equal(string.Empty, response.Content.ReadAsStringAsync().Result); - } - } - - [Fact] - public async Task OpaqueUpgrade_NullCallback_Throws() - { - using (CreateServer(env => - { - try - { - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - opaqueUpgrade(new Dictionary(), null); - } - catch (Exception ex) - { - byte[] body = Encoding.UTF8.GetBytes(ex.ToString()); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); - } - return Task.FromResult(0); - })) - { - HttpResponseMessage response = await SendRequestAsync(Address); - Assert.Equal(200, (int)response.StatusCode); - Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); - Assert.Contains("callback", response.Content.ReadAsStringAsync().Result); - } - } - [Fact] public async Task OpaqueUpgrade_AfterHeadersSent_Throws() { - bool? upgradeThrew = null; - using (CreateServer(env => + using (var server = Utilities.CreateHttpServer()) { + Task clientTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); byte[] body = Encoding.UTF8.GetBytes("Hello World"); - env.Get("owin.ResponseBody").Write(body, 0, body.Length); - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - try - { - opaqueUpgrade(null, _ => Task.FromResult(0)); - upgradeThrew = false; - } - catch (InvalidOperationException) - { - upgradeThrew = true; - } - return Task.FromResult(0); - })) - { - HttpResponseMessage response = await SendRequestAsync(Address); + context.Response.Body.Write(body, 0, body.Length); + + context.Response.Headers["Upgrade"] = new[] { "WebSocket" }; // Win8.1 blocks anything but WebSocket + Assert.ThrowsAsync(async () => await context.UpgradeAsync()); + context.Dispose(); + HttpResponseMessage response = await clientTask; Assert.Equal(200, (int)response.StatusCode); Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); - Assert.True(upgradeThrew.Value); + Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); } } [Fact] public async Task OpaqueUpgrade_GetUpgrade_Success() { - ManualResetEvent waitHandle = new ManualResetEvent(false); - bool? callbackInvoked = null; - using (CreateServer(env => + using (var server = Utilities.CreateHttpServer()) { - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Upgrade"] = new string[] { "websocket" }; // Win8.1 blocks anything but WebSockets - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - opaqueUpgrade(null, opqEnv => - { - callbackInvoked = true; - waitHandle.Set(); - return Task.FromResult(0); - }); - return Task.FromResult(0); - })) - { - using (Stream stream = await SendOpaqueRequestAsync("GET", Address)) - { - Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); - Assert.True(callbackInvoked.HasValue, "CallbackInvoked not set"); - Assert.True(callbackInvoked.Value, "Callback not invoked"); - } + Task clientTask = SendOpaqueRequestAsync("GET", Address); + + var context = await server.GetContextAsync(); + Assert.True(context.IsUpgradableRequest); + context.Response.Headers["Upgrade"] = new[] { "WebSocket" }; // Win8.1 blocks anything but WebSocket + Stream serverStream = await context.UpgradeAsync(); + Assert.True(serverStream.CanRead); + Assert.True(serverStream.CanWrite); + Stream clientStream = await clientTask; + serverStream.Dispose(); + context.Dispose(); + clientStream.Dispose(); } } @@ -158,30 +80,32 @@ namespace Microsoft.Net.Server [InlineData("PUT", "Content-Length: 0")] public async Task OpaqueUpgrade_VariousMethodsUpgradeSendAndReceive_Success(string method, string extraHeader) { - using (CreateServer(env => + using (var server = Utilities.CreateHttpServer()) { - var responseHeaders = env.Get>("owin.ResponseHeaders"); - responseHeaders["Upgrade"] = new string[] { "WebSocket" }; // Win8.1 blocks anything but WebSockets - OpaqueUpgrade opaqueUpgrade = env.Get("opaque.Upgrade"); - opaqueUpgrade(null, async opqEnv => - { - Stream opaqueStream = opqEnv.Get("opaque.Stream"); + Task clientTask = SendOpaqueRequestAsync(method, Address, extraHeader); - byte[] buffer = new byte[100]; - int read = await opaqueStream.ReadAsync(buffer, 0, buffer.Length); + var context = await server.GetContextAsync(); + Assert.True(context.IsUpgradableRequest); + context.Response.Headers["Upgrade"] = new[] { "WebSocket" }; // Win8.1 blocks anything but WebSocket + Stream serverStream = await context.UpgradeAsync(); + Stream clientStream = await clientTask; - await opaqueStream.WriteAsync(buffer, 0, read); - }); - return Task.FromResult(0); - })) - { - using (Stream stream = await SendOpaqueRequestAsync(method, Address, extraHeader)) - { - byte[] data = new byte[100]; - stream.WriteAsync(data, 0, 49).Wait(); - int read = stream.ReadAsync(data, 0, data.Length).Result; - Assert.Equal(49, read); - } + byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; + await clientStream.WriteAsync(clientBuffer, 0, 3); + + byte[] serverBuffer = new byte[clientBuffer.Length]; + int read = await serverStream.ReadAsync(serverBuffer, 0, serverBuffer.Length); + Assert.Equal(clientBuffer, serverBuffer); + + await serverStream.WriteAsync(serverBuffer, 0, read); + + byte[] clientEchoBuffer = new byte[clientBuffer.Length]; + read = await clientStream.ReadAsync(clientEchoBuffer, 0, clientEchoBuffer.Length); + Assert.Equal(clientBuffer, clientEchoBuffer); + + serverStream.Dispose(); + context.Dispose(); + clientStream.Dispose(); } } @@ -193,54 +117,19 @@ namespace Microsoft.Net.Server [InlineData("PUT", "Transfer-Encoding: chunked")] [InlineData("CUSTOMVERB", "Content-Length: 10")] [InlineData("CUSTOMVERB", "Transfer-Encoding: chunked")] - public void OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) + public async Task OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) { - OpaqueUpgrade opaqueUpgrade = null; - using (CreateServer(env => + using (var server = Utilities.CreateHttpServer()) { - opaqueUpgrade = env.Get("opaque.Upgrade"); - if (opaqueUpgrade == null) - { - throw new NotImplementedException(); - } - opaqueUpgrade(null, opqEnv => Task.FromResult(0)); - return Task.FromResult(0); - })) - { - Assert.Throws(() => - { - try - { - return SendOpaqueRequestAsync(method, Address, extraHeader).Result; - } - catch (AggregateException ag) - { - throw ag.GetBaseException(); - } - }); - Assert.Null(opaqueUpgrade); + var clientTask = SendOpaqueRequestAsync(method, Address, extraHeader); + var context = await server.GetContextAsync(); + Assert.False(context.IsUpgradableRequest); + context.Dispose(); + + await Assert.ThrowsAsync(async () => await clientTask); } } - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - OwinServerFactory.Initialize(properties); - - return OwinServerFactory.Create(app, properties); - } - private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) @@ -318,5 +207,4 @@ namespace Microsoft.Net.Server } } } -} -*/ \ No newline at end of file +} \ No newline at end of file From a3dfa41372f135117d8c02fce452f35920d78b5d Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 17 Jun 2014 16:11:44 -0700 Subject: [PATCH 065/597] Add WebSocket tests. Fix Connection header. --- .../RequestProcessing/Response.cs | 12 +- ...t.Server.WebListener.FunctionalTests.kproj | 4 +- .../WebSocketTests.cs | 160 ++++++++++++++++++ ...Microsoft.Net.Server.FunctionalTests.kproj | 4 +- .../WebSocketTests.cs | 99 +++++++++++ 5 files changed, 271 insertions(+), 8 deletions(-) create mode 100644 test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs create mode 100644 test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs diff --git a/src/Microsoft.Net.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Server/RequestProcessing/Response.cs index 119cec39a2..22d3d19f71 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Response.cs @@ -377,7 +377,7 @@ namespace Microsoft.Net.Server */ uint statusCode; uint bytesSent; - List pinnedHeaders = SerializeHeaders(); + List pinnedHeaders = SerializeHeaders(isOpaqueUpgrade); try { if (pDataChunk != null) @@ -589,7 +589,7 @@ namespace Microsoft.Net.Server return flags; } - private List SerializeHeaders() + private List SerializeHeaders(bool isOpaqueUpgrade) { UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; @@ -623,7 +623,9 @@ namespace Microsoft.Net.Server // See if this is an unknown header lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); - if (lookup == -1) + // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. + if (lookup == -1 || + (isOpaqueUpgrade && lookup == (int)UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { numUnknownHeaders += headerPair.Value.Length; } @@ -649,7 +651,9 @@ namespace Microsoft.Net.Server string[] headerValues = headerPair.Value; lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); - if (lookup == -1) + // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. + if (lookup == -1 || + (isOpaqueUpgrade && lookup == (int)UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { if (unknownHeaders == null) { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj index 6f6987bdb0..afd9e549f3 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj @@ -20,6 +20,7 @@ + @@ -36,5 +37,4 @@ - - + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs new file mode 100644 index 0000000000..1720bddd0a --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -0,0 +1,160 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Net.Http; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.PipelineCore; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener +{ + public class WebSocketTests + { + private const string Address = "http://localhost:8080/"; + private const string WsAddress = "ws://localhost:8080/"; + + [Fact] + public async Task WebSocketTests_SupportKeys_Present() + { + using (Utilities.CreateHttpServer(env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + try + { + var webSocketFeature = httpContext.GetFeature(); + Assert.NotNull(webSocketFeature); + } + catch (Exception ex) + { + return httpContext.Response.WriteAsync(ex.ToString()); + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(0, response.Content.Headers.ContentLength); + Assert.Equal(string.Empty, response.Content.ReadAsStringAsync().Result); + } + } + + [Fact] + public async Task WebSocketTests_AfterHeadersSent_Throws() + { + bool? upgradeThrew = null; + using (Utilities.CreateHttpServer(async env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + await httpContext.Response.WriteAsync("Hello World"); + try + { + var webSocketFeature = httpContext.GetFeature(); + Assert.NotNull(webSocketFeature); + await webSocketFeature.AcceptAsync(null); + upgradeThrew = false; + } + catch (InvalidOperationException) + { + upgradeThrew = true; + } + })) + { + HttpResponseMessage response = await SendRequestAsync(Address); + Assert.Equal(200, (int)response.StatusCode); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.True(upgradeThrew.Value); + } + } + + [Fact] + public async Task WebSocketAccept_Success() + { + ManualResetEvent waitHandle = new ManualResetEvent(false); + bool? upgraded = null; + using (Utilities.CreateHttpServer(async env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var webSocketFeature = httpContext.GetFeature(); + Assert.NotNull(webSocketFeature); + Assert.True(webSocketFeature.IsWebSocketRequest); + await webSocketFeature.AcceptAsync(null); + upgraded = true; + waitHandle.Set(); + })) + { + using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(WsAddress)) + { + Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); + Assert.True(upgraded.HasValue, "Upgraded not set"); + Assert.True(upgraded.Value, "Upgrade failed"); + } + } + } + + [Fact] + public async Task WebSocketAccept_SendAndReceive_Success() + { + byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; + using (Utilities.CreateHttpServer(async env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + var webSocketFeature = httpContext.GetFeature(); + Assert.NotNull(webSocketFeature); + Assert.True(webSocketFeature.IsWebSocketRequest); + var serverWebSocket = await webSocketFeature.AcceptAsync(null); + + byte[] serverBuffer = new byte[clientBuffer.Length]; + var result = await serverWebSocket.ReceiveAsync(new ArraySegment(serverBuffer, 0, serverBuffer.Length), CancellationToken.None); + Assert.Equal(clientBuffer, serverBuffer); + + await serverWebSocket.SendAsync(new ArraySegment(serverBuffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); + + })) + { + using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(WsAddress)) + { + await clientWebSocket.SendAsync(new ArraySegment(clientBuffer, 0, 3), WebSocketMessageType.Binary, true, CancellationToken.None); + + byte[] clientEchoBuffer = new byte[clientBuffer.Length]; + var result = await clientWebSocket.ReceiveAsync(new ArraySegment(clientEchoBuffer), CancellationToken.None); + Assert.Equal(clientBuffer, clientEchoBuffer); + } + } + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + + private async Task SendWebSocketRequestAsync(string address) + { + ClientWebSocket client = new ClientWebSocket(); + await client.ConnectAsync(new Uri(address), CancellationToken.None); + return client; + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj index 3de1aacf05..228bd0ad9a 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj +++ b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj @@ -20,6 +20,7 @@ + @@ -36,5 +37,4 @@ - - + \ No newline at end of file diff --git a/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs new file mode 100644 index 0000000000..946aabec14 --- /dev/null +++ b/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Net.Http; +using System.Net.WebSockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Server +{ + public class WebSocketTests + { + private const string Address = "http://localhost:8080/"; + private const string WsAddress = "ws://localhost:8080/"; + + [Fact] + public async Task WebSocketAccept_AfterHeadersSent_Throws() + { + using (var server = Utilities.CreateHttpServer()) + { + Task clientTask = SendRequestAsync(Address); + + var context = await server.GetContextAsync(); + byte[] body = Encoding.UTF8.GetBytes("Hello World"); + context.Response.Body.Write(body, 0, body.Length); + + Assert.ThrowsAsync(async () => await context.AcceptWebSocketAsync()); + context.Dispose(); + HttpResponseMessage response = await clientTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); + } + } + + [Fact] + public async Task WebSocketAccept_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task clientTask = SendWebSocketRequestAsync(WsAddress); + + var context = await server.GetContextAsync(); + Assert.True(context.IsUpgradableRequest); + WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); + WebSocket clientWebSocket = await clientTask; + serverWebSocket.Dispose(); + clientWebSocket.Dispose(); + } + } + + [Fact] + public async Task WebSocketAccept_SendAndReceive_Success() + { + using (var server = Utilities.CreateHttpServer()) + { + Task clientTask = SendWebSocketRequestAsync(WsAddress); + + var context = await server.GetContextAsync(); + Assert.True(context.IsWebSocketRequest); + WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); + WebSocket clientWebSocket = await clientTask; + + byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; + await clientWebSocket.SendAsync(new ArraySegment(clientBuffer, 0, 3), WebSocketMessageType.Binary, true, CancellationToken.None); + + byte[] serverBuffer = new byte[clientBuffer.Length]; + var result = await serverWebSocket.ReceiveAsync(new ArraySegment(serverBuffer, 0, serverBuffer.Length), CancellationToken.None); + Assert.Equal(clientBuffer, serverBuffer); + + await serverWebSocket.SendAsync(new ArraySegment(serverBuffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); + + byte[] clientEchoBuffer = new byte[clientBuffer.Length]; + result = await clientWebSocket.ReceiveAsync(new ArraySegment(clientEchoBuffer), CancellationToken.None); + Assert.Equal(clientBuffer, clientEchoBuffer); + + serverWebSocket.Dispose(); + clientWebSocket.Dispose(); + } + } + + private async Task SendRequestAsync(string uri) + { + using (HttpClient client = new HttpClient()) + { + return await client.GetAsync(uri); + } + } + + private async Task SendWebSocketRequestAsync(string address) + { + ClientWebSocket client = new ClientWebSocket(); + await client.ConnectAsync(new Uri(address), CancellationToken.None); + return client; + } + } +} \ No newline at end of file From 577b074024ad629846615affe7a27d8f713fbd49 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 18 Jun 2014 09:11:14 -0700 Subject: [PATCH 066/597] WebSockets cleanup. --- .../FeatureContext.cs | 10 +- .../RequestProcessing/RequestContext.cs | 4 +- .../Microsoft.Net.WebSockets.kproj | 2 - .../WebSocketHelpers.cs | 21 +++ .../WebSocketMiddleware.cs | 159 ------------------ src/Microsoft.Net.WebSockets/build.cmd | 3 - 6 files changed, 30 insertions(+), 169 deletions(-) delete mode 100644 src/Microsoft.Net.WebSockets/WebSocketMiddleware.cs delete mode 100644 src/Microsoft.Net.WebSockets/build.cmd diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 720ed6e51c..773f35e8ec 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -26,6 +26,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.HttpFeature; using Microsoft.Net.Server; +using Microsoft.Net.WebSockets; namespace Microsoft.AspNet.Server.WebListener { @@ -94,9 +95,12 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpSendFileFeature), this); _features.Add(typeof(IHttpRequestLifetimeFeature), this); - // TODO: If Win8+ - _features.Add(typeof(IHttpOpaqueUpgradeFeature), this); - _features.Add(typeof(IHttpWebSocketFeature), this); + // Win8+ + if (WebSocketHelpers.AreWebSocketsSupported) + { + _features.Add(typeof(IHttpOpaqueUpgradeFeature), this); + _features.Add(typeof(IHttpWebSocketFeature), this); + } // TODO: // _environment.CallCancelled = _cts.Token; diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index ad3d7fc7e8..07f0df4fab 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -255,14 +255,14 @@ namespace Microsoft.Net.Server { return AcceptWebSocketAsync(null, WebSocketHelpers.DefaultReceiveBufferSize, - WebSocket.DefaultKeepAliveInterval); + WebSocketHelpers.DefaultKeepAliveInterval); } public Task AcceptWebSocketAsync(string subProtocol) { return AcceptWebSocketAsync(subProtocol, WebSocketHelpers.DefaultReceiveBufferSize, - WebSocket.DefaultKeepAliveInterval); + WebSocketHelpers.DefaultKeepAliveInterval); } public Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval) diff --git a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj index 031b4e912b..0d270aef1d 100644 --- a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj +++ b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj @@ -18,7 +18,6 @@ 2.0 - @@ -43,7 +42,6 @@ - diff --git a/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs b/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs index 7d61cff7a1..026f295077 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs @@ -61,6 +61,7 @@ namespace Microsoft.Net.WebSockets internal static readonly ArraySegment EmptyPayload = new ArraySegment(new byte[] { }, 0, 0); private static readonly Random KeyGenerator = new Random(); + private static TimeSpan? _defaultKeepAliveInterval; public static bool AreWebSocketsSupported { @@ -70,6 +71,26 @@ namespace Microsoft.Net.WebSockets } } + public static TimeSpan DefaultKeepAliveInterval + { + get + { + if (!_defaultKeepAliveInterval.HasValue) + { + if (AreWebSocketsSupported) + { + _defaultKeepAliveInterval = new TimeSpan?(UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketGetDefaultKeepAliveInterval()); + } + else + { + _defaultKeepAliveInterval = new TimeSpan?(Timeout.InfiniteTimeSpan); + } + } + return _defaultKeepAliveInterval.Value; + } + } + + public static bool IsValidWebSocketKey(string key) { if (string.IsNullOrWhiteSpace(key)) diff --git a/src/Microsoft.Net.WebSockets/WebSocketMiddleware.cs b/src/Microsoft.Net.WebSockets/WebSocketMiddleware.cs deleted file mode 100644 index bac7e7cf32..0000000000 --- a/src/Microsoft.Net.WebSockets/WebSocketMiddleware.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. -/* TODO: -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.WebSockets; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.HttpFeature; -using Microsoft.Net.WebSockets; - -namespace Microsoft.AspNet.WebSockets -{ - public class WebSocketMiddleware - { - private RequestDelegate _next; - - public WebSocketMiddleware(RequestDelegate next) - { - _next = next; - } - - public Task Invoke(HttpContext context) - { - // Detect if an opaque upgrade is available, and if websocket upgrade headers are present. - // If so, add a websocket upgrade. - var upgradeFeature = context.GetFeature(); - if (upgradeFeature != null) - { - context.SetFeature(new UpgradeHandshake(context, upgradeFeature)); - } - - return _next(context); - } - - private class UpgradeHandshake : IHttpWebSocketFeature - { - private HttpContext _context; - private IHttpOpaqueUpgradeFeature _upgrade; - - private string _subProtocol; - private int _receiveBufferSize = WebSocketHelpers.DefaultReceiveBufferSize; - private TimeSpan _keepAliveInterval = WebSocket.DefaultKeepAliveInterval; - private ArraySegment? _internalBuffer; - - internal UpgradeHandshake(HttpContext context, IHttpOpaqueUpgradeFeature upgrade) - { - _context = context; - _upgrade = upgrade; - } - - public bool IsWebSocketRequest - { - get - { - // Headers and values: - // Connection: Upgrade - // Upgrade: WebSocket - // Sec-WebSocket-Version: (WebSocketProtocolComponent.SupportedVersion) - // Sec-WebSocket-Key: (hash, see WebSocketHelpers.GetSecWebSocketAcceptString) - // Sec-WebSocket-Protocol: (optional, list) - IList connectionHeaders = _context.Request.Headers.GetCommaSeparatedValues(HttpKnownHeaderNames.Connection); // "Upgrade, KeepAlive" - string upgradeHeader = _context.Request.Headers[HttpKnownHeaderNames.Upgrade]; - string versionHeader = _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - string keyHeader = _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - - if (connectionHeaders != null && connectionHeaders.Count > 0 - && connectionHeaders.Contains(HttpKnownHeaderNames.Upgrade, StringComparer.OrdinalIgnoreCase) - && string.Equals(upgradeHeader, WebSocketHelpers.WebSocketUpgradeToken, StringComparison.OrdinalIgnoreCase) - && string.Equals(versionHeader, UnsafeNativeMethods.WebSocketProtocolComponent.SupportedVersion, StringComparison.OrdinalIgnoreCase) - && !string.IsNullOrWhiteSpace(keyHeader)) - { - return true; - } - return false; - } - } - - public async Task AcceptAsync(IWebSocketAcceptContext acceptContext) - { - // Get options - if (acceptContext != null) - { - _subProtocol = acceptContext.SubProtocol; - } - - var advancedAcceptContext = acceptContext as WebSocketAcceptContext; - if (advancedAcceptContext != null) - { - if (advancedAcceptContext.ReceiveBufferSize.HasValue) - { - _receiveBufferSize = advancedAcceptContext.ReceiveBufferSize.Value; - } - if (advancedAcceptContext.KeepAliveInterval.HasValue) - { - _keepAliveInterval = advancedAcceptContext.KeepAliveInterval.Value; - } - _internalBuffer = advancedAcceptContext.Buffer; - } - - if (!_internalBuffer.HasValue) - { - _internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(_receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - } - - // Set WebSocket upgrade response headers - - string outgoingSecWebSocketProtocolString; - bool shouldSendSecWebSocketProtocolHeader = - WebSocketHelpers.ProcessWebSocketProtocolHeader( - _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol], - _subProtocol, - out outgoingSecWebSocketProtocolString); - - if (shouldSendSecWebSocketProtocolHeader) - { - _context.Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = outgoingSecWebSocketProtocolString; - } - - string secWebSocketKey = _context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); - - _context.Response.Headers[HttpKnownHeaderNames.Connection] = HttpKnownHeaderNames.Upgrade; - _context.Response.Headers[HttpKnownHeaderNames.Upgrade] = WebSocketHelpers.WebSocketUpgradeToken; - _context.Response.Headers[HttpKnownHeaderNames.SecWebSocketAccept] = secWebSocketAccept; - - // 101 Switching Protocols; - Stream opaqueTransport = await _upgrade.UpgradeAsync(); - return new ServerWebSocket(opaqueTransport, _subProtocol, _receiveBufferSize, _keepAliveInterval, _internalBuffer.Value); - } - } - - public class WebSocketAcceptContext : IWebSocketAcceptContext - { - public string SubProtocol { get; set; } - public int? ReceiveBufferSize { get; set; } - public TimeSpan? KeepAliveInterval { get; set; } - public ArraySegment? Buffer { get; set; } - } - } -}*/ \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/build.cmd b/src/Microsoft.Net.WebSockets/build.cmd deleted file mode 100644 index 110694d575..0000000000 --- a/src/Microsoft.Net.WebSockets/build.cmd +++ /dev/null @@ -1,3 +0,0 @@ -rem set TARGET_FRAMEWORK=k10 -@call ..\..\packages\ProjectK.0.0.1-pre-30121-096\tools\k build -pause \ No newline at end of file From 07fc434cab51a1e322ee3e334ec0c8cb8f90d4ca Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 18 Jun 2014 16:09:05 -0700 Subject: [PATCH 067/597] Cleanup sample, #regions, dependencies. --- samples/HelloWorld/Program.cs | 11 ++--- samples/SelfHostServer/project.json | 2 +- .../FeatureContext.cs | 40 +++++-------------- .../project.json | 4 +- src/Microsoft.Net.WebSockets/project.json | 2 +- 5 files changed, 19 insertions(+), 40 deletions(-) diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 65336e9be3..3eb30c4f7e 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -19,13 +19,14 @@ using System; using System.Net.WebSockets; using System.Text; using System.Threading; +using System.Threading.Tasks; using Microsoft.Net.Server; namespace HelloWorld { public class Program { - public static void Main(string[] args) + public static async Task Main(string[] args) { using (WebListener listener = new WebListener()) { @@ -35,7 +36,7 @@ namespace HelloWorld Console.WriteLine("Running..."); while (true) { - RequestContext context = listener.GetContextAsync().Result; + RequestContext context = await listener.GetContextAsync(); Console.WriteLine("Accepted"); // Context: @@ -78,9 +79,9 @@ namespace HelloWorld if (context.IsWebSocketRequest) { Console.WriteLine("WebSocket"); - WebSocket webSocket = context.AcceptWebSocketAsync().Result; - webSocket.SendAsync(new ArraySegment(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None).Wait(); - webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Goodbye", CancellationToken.None).Wait(); + WebSocket webSocket = await context.AcceptWebSocketAsync(); + await webSocket.SendAsync(new ArraySegment(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None); + await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Goodbye", CancellationToken.None); webSocket.Dispose(); } else diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 002bc7304b..845c594e63 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -6,7 +6,7 @@ "Microsoft.AspNet.Server.WebListener": "", "Microsoft.Net.Server": "" }, - "commands": { "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:8080" }, + "commands": { "web": "Microsoft.AspNet.Hosting --server=Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:8080" }, "configurations": { "net45": { }, diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 773f35e8ec..0a92682721 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -114,8 +114,6 @@ namespace Microsoft.AspNet.Server.WebListener */ } - #region IHttpRequestFeature - Stream IHttpRequestFeature.Body { get @@ -231,8 +229,7 @@ namespace Microsoft.AspNet.Server.WebListener } set { _scheme = value; } } - #endregion - #region IHttpConnectionFeature + bool IHttpConnectionFeature.IsLocal { get @@ -297,8 +294,7 @@ namespace Microsoft.AspNet.Server.WebListener } set { _remotePort = value; } } - #endregion - #region IHttpTransportLayerSecurityFeature + X509Certificate IHttpTransportLayerSecurityFeature.ClientCertificate { get @@ -319,8 +315,7 @@ namespace Microsoft.AspNet.Server.WebListener _clientCert = await Request.GetClientCertificateAsync(); } } - #endregion - #region IHttpResponseFeature + Stream IHttpResponseFeature.Body { get @@ -363,48 +358,33 @@ namespace Microsoft.AspNet.Server.WebListener get { return Response.StatusCode; } set { Response.StatusCode = value; } } - #endregion - #region IHttpSendFileFeature Task IHttpSendFileFeature.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) { return Response.SendFileAsync(path, offset, length, cancellation); } - #endregion - #region IHttpRequestLifetimeFeature - - public CancellationToken OnRequestAborted + CancellationToken IHttpRequestLifetimeFeature.OnRequestAborted { get { return _requestContext.DisconnectToken; } } - public void Abort() + void IHttpRequestLifetimeFeature.Abort() { _requestContext.Abort(); } - #endregion - #region IHttpOpaqueUpgradeFeature - - public bool IsUpgradableRequest + bool IHttpOpaqueUpgradeFeature.IsUpgradableRequest { get { return _requestContext.IsUpgradableRequest; } } - public Task UpgradeAsync() + Task IHttpOpaqueUpgradeFeature.UpgradeAsync() { - if (!IsUpgradableRequest) - { - throw new InvalidOperationException("This request cannot be upgraded."); - } return _requestContext.UpgradeAsync(); } - #endregion - #region IHttpWebSocketFeature - - public bool IsWebSocketRequest + bool IHttpWebSocketFeature.IsWebSocketRequest { get { @@ -412,7 +392,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - public Task AcceptAsync(IWebSocketAcceptContext context) + Task IHttpWebSocketFeature.AcceptAsync(IWebSocketAcceptContext context) { // TODO: Advanced params string subProtocol = null; @@ -422,7 +402,5 @@ namespace Microsoft.AspNet.Server.WebListener } return _requestContext.AcceptWebSocketAsync(subProtocol); } - - #endregion } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index e7840b9642..44d1db4f1c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -7,7 +7,8 @@ "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", "Microsoft.Framework.Logging": "0.1-alpha-*", - "Microsoft.Net.Server" : "" + "Microsoft.Net.Server" : "", + "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*" }, "compilationOptions": { "allowUnsafe": true @@ -16,7 +17,6 @@ "net45": {}, "k10": { "dependencies": { - "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*", "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.0.0", "System.Collections.Concurrent": "4.0.0.0", diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index c3b93c599f..12505a3def 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,13 +1,13 @@ { "version": "0.1-alpha-*", "dependencies": { + "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*" }, "compilationOptions" : { "allowUnsafe": true }, "configurations": { "net45" : { }, "k10" : { "dependencies": { - "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*", "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.0.0", "System.Collections.Concurrent": "4.0.0.0", From ecfd1bbe6045b1875ba1987afdeb32181a9ad9d4 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 19 Jun 2014 09:47:29 -0700 Subject: [PATCH 068/597] Removed System.IO.FileSystem.Primitives dependency --- samples/SelfHostServer/project.json | 3 +-- src/Microsoft.Net.Server/project.json | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 845c594e63..7f6ec09eda 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -18,8 +18,7 @@ "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", - "System.IO.FileSystem": "4.0.0.0", - "System.IO.FileSystem.Primitives": "4.0.0.0", + "System.IO.FileSystem": "4.0.10.0", "System.Linq": "4.0.0.0", "System.Reflection": "4.0.10.0", "System.Resources.ResourceManager": "4.0.0.0", diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Server/project.json index 0316ca03aa..7a6f7cc088 100644 --- a/src/Microsoft.Net.Server/project.json +++ b/src/Microsoft.Net.Server/project.json @@ -21,7 +21,6 @@ "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", "System.IO.FileSystem": "4.0.10.0", - "System.IO.FileSystem.Primitives": "4.0.20.0", "System.Linq": "4.0.0.0", "System.Net.Primitives": "4.0.10.0", "System.Reflection": "4.0.10.0", From 741d5b57ee9a517a2e941b0f90e1e074c04f2236 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 19 Jun 2014 11:55:37 -0700 Subject: [PATCH 069/597] Include client certificate feature renames. --- .../FeatureContext.cs | 9 +++++---- .../HttpsTests.cs | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 0a92682721..195dbdc82e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Server.WebListener IHttpConnectionFeature, IHttpResponseFeature, IHttpSendFileFeature, - IHttpTransportLayerSecurityFeature, + IHttpClientCertificateFeature, IHttpRequestLifetimeFeature, IHttpWebSocketFeature, IHttpOpaqueUpgradeFeature @@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener if (Request.IsSecureConnection) { // TODO: Should this feature be conditional? Should we add this for HTTP requests? - _features.Add(typeof(IHttpTransportLayerSecurityFeature), this); + _features.Add(typeof(IHttpClientCertificateFeature), this); } _features.Add(typeof(IHttpResponseFeature), this); _features.Add(typeof(IHttpSendFileFeature), this); @@ -295,7 +295,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _remotePort = value; } } - X509Certificate IHttpTransportLayerSecurityFeature.ClientCertificate + X509Certificate IHttpClientCertificateFeature.ClientCertificate { get { @@ -308,12 +308,13 @@ namespace Microsoft.AspNet.Server.WebListener set { _clientCert = value; } } - async Task IHttpTransportLayerSecurityFeature.LoadAsync() + async Task IHttpClientCertificateFeature.GetClientCertificateAsync() { if (_clientCert == null) { _clientCert = await Request.GetClientCertificateAsync(); } + return _clientCert; } Stream IHttpResponseFeature.Body diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 1257d82d7b..08e662a2f3 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -85,9 +85,9 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var tls = httpContext.GetFeature(); + var tls = httpContext.GetFeature(); Assert.NotNull(tls); - await tls.LoadAsync(); + await tls.GetClientCertificateAsync(); Assert.Null(tls.ClientCertificate); })) { @@ -102,9 +102,9 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var tls = httpContext.GetFeature(); + var tls = httpContext.GetFeature(); Assert.NotNull(tls); - await tls.LoadAsync(); + await tls.GetClientCertificateAsync(); Assert.NotNull(tls.ClientCertificate); })) { From 7a9590e8d54963a540f4504ce09a57875905e054 Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Thu, 19 Jun 2014 11:43:53 -0700 Subject: [PATCH 070/597] Bump version to 1.0.0-* --- samples/HelloWorld/project.json | 1 - samples/SelfHostServer/project.json | 5 ++--- .../project.json | 2 +- .../project.json | 16 +++++++------- src/Microsoft.Net.Server/project.json | 4 ++-- .../project.json | 1 - .../project.json | 21 +++++++------------ .../project.json | 7 +------ 8 files changed, 22 insertions(+), 35 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 5dd850e16e..e711f3f228 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,5 +1,4 @@ { - "version" : "0.1-alpha-*", "dependencies": { "Microsoft.Net.Server" : "" }, diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 7f6ec09eda..fe75325e0a 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,8 +1,7 @@ { - "version" : "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Hosting": "0.1-alpha-*", - "Microsoft.AspNet.Http": "0.1-alpha-*", + "Microsoft.AspNet.Hosting": "1.0.0-*", + "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "", "Microsoft.Net.Server": "" }, diff --git a/src/Microsoft.AspNet.Security.Windows/project.json b/src/Microsoft.AspNet.Security.Windows/project.json index 599c58c415..555d2501cd 100644 --- a/src/Microsoft.AspNet.Security.Windows/project.json +++ b/src/Microsoft.AspNet.Security.Windows/project.json @@ -1,5 +1,5 @@ { - "version": "0.1-alpha-*", + "version": "1.0.0-*", "dependencies": { }, "compilationOptions" : { "allowUnsafe": true }, diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 44d1db4f1c..d7d1049954 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,14 +1,14 @@ { - "version": "0.1-alpha-*", + "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNet.FeatureModel": "0.1-alpha-*", - "Microsoft.AspNet.Hosting": "0.1-alpha-*", - "Microsoft.AspNet.Http": "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature": "0.1-alpha-*", - "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", - "Microsoft.Framework.Logging": "0.1-alpha-*", + "Microsoft.AspNet.FeatureModel": "1.0.0-*", + "Microsoft.AspNet.Hosting": "1.0.0-*", + "Microsoft.AspNet.Http": "1.0.0-*", + "Microsoft.AspNet.HttpFeature": "1.0.0-*", + "Microsoft.Framework.ConfigurationModel": "1.0.0-*", + "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Net.Server" : "", - "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*" + "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" }, "compilationOptions": { "allowUnsafe": true diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Server/project.json index 7a6f7cc088..97d78aa066 100644 --- a/src/Microsoft.Net.Server/project.json +++ b/src/Microsoft.Net.Server/project.json @@ -1,7 +1,7 @@ { - "version": "0.1-alpha-*", + "version": "1.0.0-*", "dependencies": { - "Microsoft.Framework.Logging": "0.1-alpha-*", + "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Net.WebSockets": "" }, "compilationOptions": { diff --git a/test/Microsoft.AspNet.Security.Windows.Test/project.json b/test/Microsoft.AspNet.Security.Windows.Test/project.json index 90274d6696..0b61c27922 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/project.json +++ b/test/Microsoft.AspNet.Security.Windows.Test/project.json @@ -1,5 +1,4 @@ { - "version" : "0.1-alpha-*", "dependencies": { "Microsoft.AspNet.Security.Windows" : "", "Microsoft.AspNet.Server.WebListener" : "", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 57deecbd1e..36e6168fc9 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,23 +1,18 @@ { - "version" : "0.1-alpha-*", "commands": { "test": "Xunit.KRunner" }, "dependencies": { - "Microsoft.AspNet.FeatureModel" : "0.1-alpha-*", - "Microsoft.AspNet.Hosting": "0.1-alpha-*", - "Microsoft.AspNet.Http" : "0.1-alpha-*", - "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", - "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*", + "Microsoft.AspNet.FeatureModel" : "1.0.0-*", + "Microsoft.AspNet.Hosting": "1.0.0-*", + "Microsoft.AspNet.Http" : "1.0.0-*", + "Microsoft.AspNet.HttpFeature" : "1.0.0-*", + "Microsoft.AspNet.PipelineCore" : "1.0.0-*", "Microsoft.AspNet.Server.WebListener" : "", - "Microsoft.Framework.ConfigurationModel": "0.1-alpha-*", - "Microsoft.Framework.Logging": "0.1-alpha-*", + "Microsoft.Framework.ConfigurationModel": "1.0.0-*", + "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Net.Server" : "", - "xunit.abstractions": "2.0.0-aspnet-*", - "xunit.assert": "2.0.0-aspnet-*", - "xunit.core": "2.0.0-aspnet-*", - "xunit.execution": "2.0.0-aspnet-*", - "Xunit.KRunner": "0.1-alpha-*" + "Xunit.KRunner": "1.0.0-*" }, "configurations": { "net45": { diff --git a/test/Microsoft.Net.Server.FunctionalTests/project.json b/test/Microsoft.Net.Server.FunctionalTests/project.json index b49bc93e58..e070fa1cc7 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Server.FunctionalTests/project.json @@ -1,15 +1,10 @@ { - "version" : "0.1-alpha-*", "commands": { "test": "Xunit.KRunner" }, "dependencies": { "Microsoft.Net.Server" : "", - "Xunit.KRunner": "0.1-alpha-*", - "xunit.abstractions": "2.0.0-aspnet-*", - "xunit.assert": "2.0.0-aspnet-*", - "xunit.core": "2.0.0-aspnet-*", - "xunit.execution": "2.0.0-aspnet-*" + "Xunit.KRunner": "1.0.0-*" }, "configurations": { "net45": { From d803dc84d8adff27187a1f7d9feea59f82e747ef Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 20 Jun 2014 00:11:30 -0700 Subject: [PATCH 071/597] Fixed websockets version --- src/Microsoft.Net.Server/project.json | 2 +- src/Microsoft.Net.WebSockets/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Server/project.json index 97d78aa066..eeff352bdf 100644 --- a/src/Microsoft.Net.Server/project.json +++ b/src/Microsoft.Net.Server/project.json @@ -11,7 +11,7 @@ "net45": {}, "k10": { "dependencies": { - "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*", + "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.0.0", "System.Collections.Concurrent": "4.0.0.0", diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 12505a3def..c2697cb291 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,7 +1,7 @@ { "version": "0.1-alpha-*", "dependencies": { - "Microsoft.Net.WebSocketAbstractions": "0.1-alpha-*" + "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" }, "compilationOptions" : { "allowUnsafe": true }, "configurations": { From 5f9cfb8c6241be735e7ffbee938bd1fba167ed37 Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Fri, 20 Jun 2014 14:34:05 -0700 Subject: [PATCH 072/597] Updating release Nuget.config --- NuGet.Config | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index a059188b09..1ce6b9e257 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,13 +1,7 @@ - + - + - - - - - - - \ No newline at end of file + From b89a64281f29809c6e0b3d90dc3476e38012fccb Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Fri, 20 Jun 2014 14:34:06 -0700 Subject: [PATCH 073/597] Updating dev Nuget.config --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index 1ce6b9e257..f41e9c631d 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@ - + - + From e7508af2d9f34e0d9329598670fa028ec38337a4 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 26 Jun 2014 10:16:57 -0700 Subject: [PATCH 074/597] Include IHttpClientCertificateFeature changes. --- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 4 ++-- .../RequestProcessing/ClientCertLoader.cs | 3 ++- src/Microsoft.Net.Server/RequestProcessing/Request.cs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 195dbdc82e..136d3ab552 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -308,11 +308,11 @@ namespace Microsoft.AspNet.Server.WebListener set { _clientCert = value; } } - async Task IHttpClientCertificateFeature.GetClientCertificateAsync() + async Task IHttpClientCertificateFeature.GetClientCertificateAsync(CancellationToken cancellationToken) { if (_clientCert == null) { - _clientCert = await Request.GetClientCertificateAsync(); + _clientCert = await Request.GetClientCertificateAsync(cancellationToken); } return _clientCert; } diff --git a/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs index f1c4768259..3f6228db45 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs @@ -162,8 +162,9 @@ namespace Microsoft.Net.Server // ERROR_NOT_FOUND - which means the client did not provide the cert // If this is important, the server should respond with 403 forbidden // HTTP.SYS will not do this for you automatically - internal Task LoadClientCertificateAsync() + internal Task LoadClientCertificateAsync(CancellationToken cancellationToken) { + // TODO: cancellation support? Abort the request? uint size = CertBoblSize; bool retry; do diff --git a/src/Microsoft.Net.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Server/RequestProcessing/Request.cs index 2b3f4f1262..ba535acea1 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Request.cs @@ -455,7 +455,7 @@ namespace Microsoft.Net.Server // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to // enable this, but it's unclear what Http.Sys would do. - public async Task GetClientCertificateAsync() + public async Task GetClientCertificateAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (SslStatus == SslStatus.Insecure) { @@ -471,7 +471,7 @@ namespace Microsoft.Net.Server ClientCertLoader certLoader = new ClientCertLoader(RequestContext); try { - await certLoader.LoadClientCertificateAsync().SupressContext(); + await certLoader.LoadClientCertificateAsync(cancellationToken).SupressContext(); // Populate the environment. if (certLoader.ClientCert != null) { From 0103307aac5854ed209b48b63faf3028a124236d Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 26 Jun 2014 10:24:44 -0700 Subject: [PATCH 075/597] Fix https tests. --- .../HttpsTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 08e662a2f3..cbb805eb5f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -19,6 +19,7 @@ using System.IO; using System.Net.Http; using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.HttpFeature; @@ -87,7 +88,7 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); var tls = httpContext.GetFeature(); Assert.NotNull(tls); - await tls.GetClientCertificateAsync(); + await tls.GetClientCertificateAsync(CancellationToken.None); Assert.Null(tls.ClientCertificate); })) { @@ -104,7 +105,7 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); var tls = httpContext.GetFeature(); Assert.NotNull(tls); - await tls.GetClientCertificateAsync(); + await tls.GetClientCertificateAsync(CancellationToken.None); Assert.NotNull(tls.ClientCertificate); })) { From bb0fb639ae6a75cf26c55a833bd72c1950569fea Mon Sep 17 00:00:00 2001 From: David Fowler Date: Tue, 1 Jul 2014 10:31:16 -0700 Subject: [PATCH 076/597] Updated packages due to changes in security contracts --- src/Microsoft.Net.WebSockets/project.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index c2697cb291..e016a4ca4f 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -24,7 +24,8 @@ "System.Runtime.Extensions": "4.0.10.0", "System.Runtime.Handles": "4.0.0.0", "System.Runtime.InteropServices": "4.0.20.0", - "System.Security.Cryptography.HashAlgorithms.SHA1": "4.0.0.0", + "System.Security.Cryptography": "4.0.0.0", + "System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", "System.Text.Encoding.Extensions": "4.0.10.0", From 6f550d67a43603dbcf01427daa58180547653216 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 20 Jun 2014 10:10:13 -0700 Subject: [PATCH 077/597] Improve the auth infrastructure. Expose the user. --- samples/SelfHostServer/Startup.cs | 2 +- .../FeatureContext.cs | 27 ++++ .../project.json | 1 + .../AsyncAcceptContext.cs | 2 +- .../AuthenticationManager.cs | 121 ++++++++++----- .../AuthenticationTypes.cs | 11 +- .../RequestProcessing/Request.cs | 30 +--- .../RequestProcessing/RequestContext.cs | 5 +- .../RequestProcessing/Response.cs | 7 +- src/Microsoft.Net.Server/WebListener.cs | 143 ++++++++++++++---- src/Microsoft.Net.Server/project.json | 1 + .../AuthenticationTests.cs | 143 +++++++++++++----- .../Utilities.cs | 6 +- .../AuthenticationTests.cs | 140 +++++++++++------ .../Utilities.cs | 6 +- 15 files changed, 448 insertions(+), 197 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 3a6c87a4ab..917c06a5b7 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -32,7 +32,7 @@ namespace SelfHostServer public void Configure(IBuilder app) { var info = (ServerInformation)app.Server; - info.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationType.None; + info.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationTypes.AllowAnonymous; app.Run(async context => { diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 136d3ab552..f1876bcf89 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -20,11 +20,14 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Net.WebSockets; +using System.Security.Claims; using System.Security.Cryptography.X509Certificates; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.HttpFeature.Security; using Microsoft.Net.Server; using Microsoft.Net.WebSockets; @@ -38,6 +41,7 @@ namespace Microsoft.AspNet.Server.WebListener IHttpClientCertificateFeature, IHttpRequestLifetimeFeature, IHttpWebSocketFeature, + IHttpAuthenticationFeature, IHttpOpaqueUpgradeFeature { private RequestContext _requestContext; @@ -57,6 +61,8 @@ namespace Microsoft.AspNet.Server.WebListener private int? _localPort; private bool? _isLocal; private X509Certificate _clientCert; + private ClaimsPrincipal _user; + private IAuthenticationHandler _authHandler; private Stream _responseStream; private IDictionary _responseHeaders; @@ -94,6 +100,7 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpResponseFeature), this); _features.Add(typeof(IHttpSendFileFeature), this); _features.Add(typeof(IHttpRequestLifetimeFeature), this); + _features.Add(typeof(IHttpAuthenticationFeature), this); // Win8+ if (WebSocketHelpers.AreWebSocketsSupported) @@ -403,5 +410,25 @@ namespace Microsoft.AspNet.Server.WebListener } return _requestContext.AcceptWebSocketAsync(subProtocol); } + + ClaimsPrincipal IHttpAuthenticationFeature.User + { + get + { + if (_user == null) + { + _user = _requestContext.User; + } + return _user; + } + set { _user = value; } + } + + // TODO: Hook this server up as the default handler, have it issue challenges for configured auth types by name. + IAuthenticationHandler IHttpAuthenticationFeature.Handler + { + get { return _authHandler; } + set { _authHandler = value; } + } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index d7d1049954..f28e0e19e3 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -33,6 +33,7 @@ "System.Runtime.Extensions": "4.0.10.0", "System.Runtime.Handles": "4.0.0.0", "System.Runtime.InteropServices": "4.0.20.0", + "System.Security.Claims": "0.1-alpha-*", "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", diff --git a/src/Microsoft.Net.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Server/AsyncAcceptContext.cs index 71cc7952e0..f1df0bbbad 100644 --- a/src/Microsoft.Net.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Server/AsyncAcceptContext.cs @@ -91,7 +91,7 @@ namespace Microsoft.Net.Server bool stoleBlob = false; try { - if (server.ValidateRequest(asyncResult._nativeRequestContext)) + if (server.ValidateRequest(asyncResult._nativeRequestContext) && server.ValidateAuth(asyncResult._nativeRequestContext)) { stoleBlob = true; RequestContext requestContext = new RequestContext(server, asyncResult._nativeRequestContext); diff --git a/src/Microsoft.Net.Server/AuthenticationManager.cs b/src/Microsoft.Net.Server/AuthenticationManager.cs index ec3452357e..64ee0b4d7d 100644 --- a/src/Microsoft.Net.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Server/AuthenticationManager.cs @@ -25,6 +25,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Security.Claims; +using System.Security.Principal; namespace Microsoft.Net.Server { @@ -45,17 +47,17 @@ namespace Microsoft.Net.Server #endif private WebListener _server; - AuthenticationType _authTypes; + private AuthenticationTypes _authTypes; internal AuthenticationManager(WebListener listener) { _server = listener; - _authTypes = AuthenticationType.None; + _authTypes = AuthenticationTypes.AllowAnonymous; } #region Properties - public AuthenticationType AuthenticationTypes + public AuthenticationTypes AuthenticationTypes { get { @@ -68,6 +70,14 @@ namespace Microsoft.Net.Server } } + internal bool AllowAnonymous + { + get + { + return ((_authTypes & AuthenticationTypes.AllowAnonymous) == AuthenticationTypes.AllowAnonymous); + } + } + #endregion Properties private unsafe void SetServerSecurity() @@ -76,71 +86,108 @@ namespace Microsoft.Net.Server new UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO(); authInfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; - authInfo.AuthSchemes = (UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES)_authTypes; + var authTypes = (UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES)(_authTypes & ~AuthenticationTypes.AllowAnonymous); + if (authTypes != UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES.NONE) + { + authInfo.AuthSchemes = authTypes; - // TODO: - // NTLM auth sharing (on by default?) DisableNTLMCredentialCaching - // Kerberos auth sharing (off by default?) HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING - // Mutual Auth - ReceiveMutualAuth - // Digest domain and realm - HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS - // Basic realm - HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS + // TODO: + // NTLM auth sharing (on by default?) DisableNTLMCredentialCaching + // Kerberos auth sharing (off by default?) HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING + // Mutual Auth - ReceiveMutualAuth + // Digest domain and realm - HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS + // Basic realm - HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS - IntPtr infoptr = new IntPtr(&authInfo); + IntPtr infoptr = new IntPtr(&authInfo); - _server.SetUrlGroupProperty( - UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, - infoptr, (uint)AuthInfoSize); + _server.SetUrlGroupProperty( + UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, + infoptr, (uint)AuthInfoSize); + } } - internal void SetAuthenticationChallenge(Response response) + // TODO: If we're not going to support Digest then this whole list can be pre-computed and cached. + // consider even pre-serialzing and caching the bytes for the !AllowAnonymous scenario. + internal IList GenerateChallenges() { - if (_authTypes == AuthenticationType.None) - { - return; - } - IList challenges = new List(); // Order by strength. - if ((_authTypes & AuthenticationType.Kerberos) == AuthenticationType.Kerberos) + if ((_authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos) { challenges.Add("Kerberos"); } - if ((_authTypes & AuthenticationType.Negotiate) == AuthenticationType.Negotiate) + if ((_authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate) { challenges.Add("Negotiate"); } - if ((_authTypes & AuthenticationType.Ntlm) == AuthenticationType.Ntlm) + if ((_authTypes & AuthenticationTypes.Ntlm) == AuthenticationTypes.Ntlm) { challenges.Add("NTLM"); } - if ((_authTypes & AuthenticationType.Digest) == AuthenticationType.Digest) + /*if ((_authTypes & AuthenticationTypes.Digest) == AuthenticationTypes.Digest) { // TODO: throw new NotImplementedException("Digest challenge generation has not been implemented."); // challenges.Add("Digest"); - } - if ((_authTypes & AuthenticationType.Basic) == AuthenticationType.Basic) + }*/ + if ((_authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic) { // TODO: Realm challenges.Add("Basic"); } + return challenges; + } - // Append to the existing header, if any. Some clients (IE, Chrome) require each challenges to be sent on their own line/header. - string[] oldValues; - string[] newValues; - if (response.Headers.TryGetValue(HttpKnownHeaderNames.WWWAuthenticate, out oldValues)) + internal void SetAuthenticationChallenge(Response response) + { + IList challenges = GenerateChallenges(); + + if (challenges.Count > 0) { - newValues = new string[oldValues.Length + challenges.Count]; - Array.Copy(oldValues, newValues, oldValues.Length); - challenges.CopyTo(newValues, oldValues.Length); + // TODO: We need a better header API that just lets us append values. + // Append to the existing header, if any. Some clients (IE, Chrome) require each challenges to be sent on their own line/header. + string[] oldValues; + string[] newValues; + if (response.Headers.TryGetValue(HttpKnownHeaderNames.WWWAuthenticate, out oldValues)) + { + newValues = new string[oldValues.Length + challenges.Count]; + Array.Copy(oldValues, newValues, oldValues.Length); + challenges.CopyTo(newValues, oldValues.Length); + } + else + { + newValues = new string[challenges.Count]; + challenges.CopyTo(newValues, 0); + } + response.Headers[HttpKnownHeaderNames.WWWAuthenticate] = newValues; } - else + } + + internal static unsafe bool CheckAuthenticated(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* requestInfo) + { + if (requestInfo != null + && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { - newValues = new string[challenges.Count]; - challenges.CopyTo(newValues, 0); +#if NET45 + return true; +#endif } - response.Headers[HttpKnownHeaderNames.WWWAuthenticate] = newValues; + return false; + } + + internal static unsafe ClaimsPrincipal GetUser(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* requestInfo) + { + if (requestInfo != null + && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + { +#if NET45 + return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken)); +#endif + } + return new ClaimsPrincipal(new ClaimsIdentity(string.Empty)); // Anonymous / !IsAuthenticated } } } diff --git a/src/Microsoft.Net.Server/AuthenticationTypes.cs b/src/Microsoft.Net.Server/AuthenticationTypes.cs index 73e07811bd..e524d6b69c 100644 --- a/src/Microsoft.Net.Server/AuthenticationTypes.cs +++ b/src/Microsoft.Net.Server/AuthenticationTypes.cs @@ -16,21 +16,18 @@ // permissions and limitations under the License. using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Microsoft.Net.Server { [Flags] - public enum AuthenticationType + public enum AuthenticationTypes { - None = 0x0, + // None = 0x0, // None is invalid, use AllowAnonymous (which must have a non-zero value). Basic = 0x1, - Digest = 0x2, + // Digest = 0x2, // TODO: Verify this is no longer supported by Http.Sys Ntlm = 0x4, Negotiate = 0x8, Kerberos = 0x10, + AllowAnonymous = 0x1000 } } diff --git a/src/Microsoft.Net.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Server/RequestProcessing/Request.cs index ba535acea1..513f5a4f39 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Request.cs @@ -27,9 +27,11 @@ using System.Globalization; using System.IO; using System.Net; using System.Runtime.InteropServices; +using System.Security.Claims; using System.Security.Cryptography.X509Certificates; +#if NET45 using System.Security.Principal; -using System.Threading; +#endif using System.Threading.Tasks; namespace Microsoft.Net.Server @@ -66,7 +68,7 @@ namespace Microsoft.Net.Server private SocketAddress _localEndPoint; private SocketAddress _remoteEndPoint; - private IPrincipal _user; + private ClaimsPrincipal _user; private bool _isDisposed = false; @@ -140,7 +142,7 @@ namespace Microsoft.Net.Server _headers = new RequestHeaders(_nativeRequestContext); UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2* requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; - _user = GetUser(requestV2->pRequestInfo); + _user = AuthenticationManager.GetUser(requestV2->pRequestInfo); // TODO: Verbose log parameters @@ -411,31 +413,11 @@ namespace Microsoft.Net.Server } } - internal IPrincipal User + internal ClaimsPrincipal User { get { return _user; } } - private unsafe IPrincipal GetUser(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* requestInfo) - { - if (requestInfo == null - || requestInfo->InfoType != UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth) - { - return null; - } - - if (requestInfo->pInfo->AuthStatus != UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) - { - return null; - } - -#if NET45 - return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken)); -#else - return null; -#endif - } - internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod() { return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress); diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index 07f0df4fab..e0cc636bd1 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -22,13 +22,12 @@ //------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net.WebSockets; using System.Runtime.InteropServices; -using System.Security.Principal; +using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using Microsoft.Framework.Logging; @@ -72,7 +71,7 @@ namespace Microsoft.Net.Server } } - public IPrincipal User + public ClaimsPrincipal User { get { return _request.User; } } diff --git a/src/Microsoft.Net.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Server/RequestProcessing/Response.cs index 22d3d19f71..0bca230c20 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Response.cs @@ -708,7 +708,12 @@ namespace Microsoft.Net.Server } knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; - knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = +#if NET45 + (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); +#else + (uint)Marshal.SizeOf(); +#endif UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); diff --git a/src/Microsoft.Net.Server/WebListener.cs b/src/Microsoft.Net.Server/WebListener.cs index ba54332fde..a66dd103f8 100644 --- a/src/Microsoft.Net.Server/WebListener.cs +++ b/src/Microsoft.Net.Server/WebListener.cs @@ -78,6 +78,7 @@ namespace Microsoft.Net.Server private SafeHandle _requestQueueHandle; private volatile State _state; // m_State is set only within lock blocks, but often read outside locks. + private bool _ignoreWriteExceptions; private HttpServerSessionHandle _serverSessionHandle; private ulong _urlGroupId; @@ -649,7 +650,18 @@ namespace Microsoft.Net.Server // Block potential DOS attacks if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit) { - SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest); + SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest, authChallenges: null); + return false; + } + return true; + } + + internal unsafe bool ValidateAuth(NativeRequestContext requestMemory) + { + var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob; + if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) + { + SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, AuthenticationManager.GenerateChallenges()); return false; } return true; @@ -781,47 +793,116 @@ namespace Microsoft.Net.Server return cts.Token; } - private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode) + private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode, IList authChallenges) { UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2(); httpResponse.Response_V1.Version = new UnsafeNclNativeMethods.HttpApi.HTTP_VERSION(); httpResponse.Response_V1.Version.MajorVersion = (ushort)1; httpResponse.Response_V1.Version.MinorVersion = (ushort)1; - httpResponse.Response_V1.StatusCode = (ushort)httpStatusCode; - string statusDescription = HttpReasonPhrase.Get(httpStatusCode); - uint dataWritten = 0; - uint statusCode; - byte[] byteReason = HeaderEncoding.GetBytes(statusDescription); - fixed (byte* pReason = byteReason) + + List pinnedHeaders = null; + GCHandle gcHandle; + try { - httpResponse.Response_V1.pReason = (sbyte*)pReason; - httpResponse.Response_V1.ReasonLength = (ushort)byteReason.Length; - - byte[] byteContentLength = new byte[] { (byte)'0' }; - fixed (byte* pContentLength = byteContentLength) + // Copied from the multi-value headers section of SerializeHeaders + if (authChallenges != null && authChallenges.Count > 0) { - (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength; - (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; - httpResponse.Response_V1.Headers.UnknownHeaderCount = 0; + pinnedHeaders = new List(); - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( - _requestQueueHandle, - requestId, - 0, - &httpResponse, - null, - &dataWritten, - SafeLocalFree.Zero, - 0, - SafeNativeOverlapped.Zero, - IntPtr.Zero); + UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; + knownHeaderInfo = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[1]; + gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + httpResponse.pResponseInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); + + knownHeaderInfo[httpResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; + knownHeaderInfo[httpResponse.ResponseInfoCount].Length = +#if NET45 + (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); +#else + (uint)Marshal.SizeOf(); +#endif + + UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); + + header.HeaderId = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderWwwAuthenticate; + header.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // The docs say this is for www-auth only. + + UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER[authChallenges.Count]; + gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + header.KnownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + + for (int headerValueIndex = 0; headerValueIndex < authChallenges.Count; headerValueIndex++) + { + // Add Value + string headerValue = authChallenges[headerValueIndex]; + byte[] bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; + HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); + gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + nativeHeaderValues[header.KnownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + header.KnownHeaderCount++; + } + + // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. + gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + knownHeaderInfo[0].pInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); + + httpResponse.ResponseInfoCount = 1; + } + + httpResponse.Response_V1.StatusCode = (ushort)httpStatusCode; + string statusDescription = HttpReasonPhrase.Get(httpStatusCode); + uint dataWritten = 0; + uint statusCode; + byte[] byteReason = HeaderEncoding.GetBytes(statusDescription); + fixed (byte* pReason = byteReason) + { + httpResponse.Response_V1.pReason = (sbyte*)pReason; + httpResponse.Response_V1.ReasonLength = (ushort)byteReason.Length; + + byte[] byteContentLength = new byte[] { (byte)'0' }; + fixed (byte* pContentLength = byteContentLength) + { + (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength; + (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; + httpResponse.Response_V1.Headers.UnknownHeaderCount = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( + _requestQueueHandle, + requestId, + 0, + &httpResponse, + null, + &dataWritten, + SafeLocalFree.Zero, + 0, + SafeNativeOverlapped.Zero, + IntPtr.Zero); + } + } + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + // if we fail to send a 401 something's seriously wrong, abort the request + RequestContext.CancelRequest(_requestQueueHandle, requestId); } } - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + finally { - // if we fail to send a 401 something's seriously wrong, abort the request - RequestContext.CancelRequest(_requestQueueHandle, requestId); + if (pinnedHeaders != null) + { + foreach (GCHandle handle in pinnedHeaders) + { + if (handle.IsAllocated) + { + handle.Free(); + } + } + } } } diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Server/project.json index eeff352bdf..ef68434d86 100644 --- a/src/Microsoft.Net.Server/project.json +++ b/src/Microsoft.Net.Server/project.json @@ -29,6 +29,7 @@ "System.Runtime.Extensions": "4.0.10.0", "System.Runtime.Handles": "4.0.0.0", "System.Runtime.InteropServices": "4.0.20.0", + "System.Security.Claims": "0.1-alpha-*", "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index e6acd0f358..eae1a1e89e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -31,35 +31,61 @@ namespace Microsoft.AspNet.Server.WebListener private const string Address = "http://localhost:8080/"; [Theory] - [InlineData(AuthenticationType.Kerberos)] - [InlineData(AuthenticationType.Negotiate)] - [InlineData(AuthenticationType.Ntlm)] - [InlineData(AuthenticationType.Digest)] - [InlineData(AuthenticationType.Basic)] - [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | AuthenticationType.Digest | AuthenticationType.Basic)] - public async Task AuthTypes_EnabledButNotChalleneged_PassThrough(AuthenticationType authType) + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] + [InlineData(AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType) { - using (Utilities.CreateAuthServer(authType, env => + using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); return Task.FromResult(0); })) { var response = await SendRequestAsync(Address); - response.EnsureSuccessStatusCode(); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(0, response.Headers.WwwAuthenticate.Count); } } [Theory] - [InlineData(AuthenticationType.Kerberos)] - [InlineData(AuthenticationType.Negotiate)] - [InlineData(AuthenticationType.Ntlm)] - // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented - [InlineData(AuthenticationType.Basic)] - public async Task AuthType_Specify401_ChallengesAdded(AuthenticationType authType) + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented + [InlineData(AuthenticationTypes.Basic)] + public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType) { using (Utilities.CreateAuthServer(authType, env => { - new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; + throw new NotImplementedException(); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented + [InlineData(AuthenticationTypes.Basic)] + public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType) + { + using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + context.Response.StatusCode = 401; return Task.FromResult(0); })) { @@ -70,17 +96,21 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task MultipleAuthTypes_Specify401_ChallengesAdded() + public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { using (Utilities.CreateAuthServer( - AuthenticationType.Kerberos - | AuthenticationType.Negotiate - | AuthenticationType.Ntlm - /* | AuthenticationType.Digest TODO: Not implemented */ - | AuthenticationType.Basic, + AuthenticationTypes.Kerberos + | AuthenticationTypes.Negotiate + | AuthenticationTypes.Ntlm + /* | AuthenticationTypes.Digest TODO: Not implemented */ + | AuthenticationTypes.Basic + | AuthenticationTypes.AllowAnonymous, env => { - new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + context.Response.StatusCode = 401; return Task.FromResult(0); })) { @@ -89,35 +119,64 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal("Kerberos, Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } } - /* TODO: User + [Theory] - [InlineData(AuthenticationType.Kerberos)] - [InlineData(AuthenticationType.Negotiate)] - [InlineData(AuthenticationType.Ntlm)] - // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented - // [InlineData(AuthenticationType.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | / *AuthenticationType.Digest |* / AuthenticationType.Basic)] - public async Task AuthTypes_Login_Success(AuthenticationType authType) + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType) { - int requestCount = 0; - using (Utilities.CreateAuthServer(authType, env => + int requestId = 0; + using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => { - requestCount++; - / * // TODO: Expose user as feature. - object obj; - if (env.TryGetValue("server.User", out obj) && obj != null) + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + if (requestId == 0) { - return Task.FromResult(0); - }* / - new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; + Assert.False(context.User.Identity.IsAuthenticated); + context.Response.StatusCode = 401; + } + else if (requestId == 1) + { + Assert.True(context.User.Identity.IsAuthenticated); + } + else + { + throw new NotImplementedException(); + } + requestId++; return Task.FromResult(0); })) { var response = await SendRequestAsync(Address, useDefaultCredentials: true); - response.EnsureSuccessStatusCode(); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType) + { + using (Utilities.CreateAuthServer(authType, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address, useDefaultCredentials: true); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } - */ private async Task SendRequestAsync(string uri, bool useDefaultCredentials = false) { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index 1a834b99cd..8281848d57 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -35,17 +35,17 @@ namespace Microsoft.AspNet.Server.WebListener return CreateServer("https", "localhost", "9090", string.Empty, app); } - internal static IDisposable CreateAuthServer(AuthenticationType authType, AppFunc app) + internal static IDisposable CreateAuthServer(AuthenticationTypes authType, AppFunc app) { return CreateServer("http", "localhost", "8080", string.Empty, authType, app); } internal static IDisposable CreateServer(string scheme, string host, string port, string path, AppFunc app) { - return CreateServer(scheme, host, port, path, AuthenticationType.None, app); + return CreateServer(scheme, host, port, path, AuthenticationTypes.AllowAnonymous, app); } - internal static IDisposable CreateServer(string scheme, string host, string port, string path, AuthenticationType authType, AppFunc app) + internal static IDisposable CreateServer(string scheme, string host, string port, string path, AuthenticationTypes authType, AppFunc app) { var factory = new ServerFactory(loggerFactory: null); var serverInfo = (ServerInformation)factory.Initialize(configuration: null); diff --git a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs index 593575806c..ce57a86d35 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs @@ -13,39 +13,65 @@ namespace Microsoft.Net.Server private const string Address = "http://localhost:8080/"; [Theory] - [InlineData(AuthenticationType.Kerberos)] - [InlineData(AuthenticationType.Negotiate)] - [InlineData(AuthenticationType.Ntlm)] - [InlineData(AuthenticationType.Digest)] - [InlineData(AuthenticationType.Basic)] - [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | AuthenticationType.Digest | AuthenticationType.Basic)] - public async Task AuthTypes_EnabledButNotChalleneged_PassThrough(AuthenticationType authType) + [InlineData(AuthenticationTypes.AllowAnonymous)] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] + [InlineData(AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType) { - using (var server = Utilities.CreateAuthServer(authType)) + using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) { Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); context.Dispose(); var response = await responseTask; - response.EnsureSuccessStatusCode(); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(0, response.Headers.WwwAuthenticate.Count); } } [Theory] - [InlineData(AuthenticationType.Kerberos)] - [InlineData(AuthenticationType.Negotiate)] - [InlineData(AuthenticationType.Ntlm)] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented - [InlineData(AuthenticationType.Basic)] - public async Task AuthType_Specify401_ChallengesAdded(AuthenticationType authType) + [InlineData(AuthenticationTypes.Basic)] + public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType) { using (var server = Utilities.CreateAuthServer(authType)) { Task responseTask = SendRequestAsync(Address); + var contextTask = server.GetContextAsync(); // Fails when the server shuts down, the challenge happens internally. + + var response = await responseTask; + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented + [InlineData(AuthenticationTypes.Basic)] + public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType) + { + using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) + { + Task responseTask = SendRequestAsync(Address); + var context = await server.GetContextAsync(); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); context.Response.StatusCode = 401; context.Dispose(); @@ -56,18 +82,21 @@ namespace Microsoft.Net.Server } [Fact] - public async Task MultipleAuthTypes_Specify401_ChallengesAdded() + public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { using (var server = Utilities.CreateAuthServer( - AuthenticationType.Kerberos - | AuthenticationType.Negotiate - | AuthenticationType.Ntlm - /* | AuthenticationType.Digest TODO: Not implemented */ - | AuthenticationType.Basic)) + AuthenticationTypes.Kerberos + | AuthenticationTypes.Negotiate + | AuthenticationTypes.Ntlm + /* | AuthenticationTypes.Digest TODO: Not implemented */ + | AuthenticationTypes.Basic + | AuthenticationTypes.AllowAnonymous)) { Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); context.Response.StatusCode = 401; context.Dispose(); @@ -76,35 +105,58 @@ namespace Microsoft.Net.Server Assert.Equal("Kerberos, Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } } - /* TODO: User + [Theory] - [InlineData(AuthenticationType.Kerberos)] - [InlineData(AuthenticationType.Negotiate)] - [InlineData(AuthenticationType.Ntlm)] - // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented - // [InlineData(AuthenticationType.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationType.Kerberos | AuthenticationType.Negotiate | AuthenticationType.Ntlm | / *AuthenticationType.Digest |* / AuthenticationType.Basic)] - public async Task AuthTypes_Login_Success(AuthenticationType authType) + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType) { - int requestCount = 0; - using (Utilities.CreateAuthServer(authType, env => + using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) { - requestCount++; - / * // TODO: Expose user as feature. - object obj; - if (env.TryGetValue("server.User", out obj) && obj != null) - { - return Task.FromResult(0); - }* / - new DefaultHttpContext((IFeatureCollection)env).Response.StatusCode = 401; - return Task.FromResult(0); - })) - { - var response = await SendRequestAsync(Address, useDefaultCredentials: true); - response.EnsureSuccessStatusCode(); + Task responseTask = SendRequestAsync(Address, useDefaultCredentials: true); + + var context = await server.GetContextAsync(); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + context.Response.StatusCode = 401; + context.Dispose(); + + context = await server.GetContextAsync(); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.Ntlm)] + // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType) + { + using (var server = Utilities.CreateAuthServer(authType)) + { + Task responseTask = SendRequestAsync(Address, useDefaultCredentials: true); + + var context = await server.GetContextAsync(); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } - */ private async Task SendRequestAsync(string uri, bool useDefaultCredentials = false) { diff --git a/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs index c11b7596f1..e911f5baa2 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs @@ -16,17 +16,17 @@ namespace Microsoft.Net.Server return CreateServer("https", "localhost", "9090", string.Empty); } - internal static WebListener CreateAuthServer(AuthenticationType authType) + internal static WebListener CreateAuthServer(AuthenticationTypes authType) { return CreateServer("http", "localhost", "8080", string.Empty, authType); } internal static WebListener CreateServer(string scheme, string host, string port, string path) { - return CreateServer(scheme, host, port, path, AuthenticationType.None); + return CreateServer(scheme, host, port, path, AuthenticationTypes.AllowAnonymous); } - internal static WebListener CreateServer(string scheme, string host, string port, string path, AuthenticationType authType) + internal static WebListener CreateServer(string scheme, string host, string port, string path, AuthenticationTypes authType) { WebListener listener = new WebListener(); listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); From 0e197a59ed548c67c064f99eeed6421e652847ab Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 20 Jun 2014 14:19:54 -0700 Subject: [PATCH 078/597] More HTTPS tests. --- .../HttpsTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index cbb805eb5f..77b0523699 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -88,7 +88,8 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); var tls = httpContext.GetFeature(); Assert.NotNull(tls); - await tls.GetClientCertificateAsync(CancellationToken.None); + var cert = await tls.GetClientCertificateAsync(CancellationToken.None); + Assert.Null(cert); Assert.Null(tls.ClientCertificate); })) { @@ -105,7 +106,8 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); var tls = httpContext.GetFeature(); Assert.NotNull(tls); - await tls.GetClientCertificateAsync(CancellationToken.None); + var cert = await tls.GetClientCertificateAsync(CancellationToken.None); + Assert.NotNull(cert); Assert.NotNull(tls.ClientCertificate); })) { From e15fe540a87ba52129164d6f2291acda97012974 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 24 Jun 2014 10:17:29 -0700 Subject: [PATCH 079/597] Enable custom auth challenges. Integrate IAuthenticationHandler. --- .../AuthenticationHandler.cs | 148 +++++++++++ .../FeatureContext.cs | 10 +- .../Microsoft.AspNet.Server.WebListener.kproj | 1 + .../AuthenticationManager.cs | 53 +++- .../AuthenticationTypes.cs | 4 +- .../RequestProcessing/RequestContext.cs | 11 +- .../RequestProcessing/Response.cs | 2 +- src/Microsoft.Net.Server/WebListener.cs | 3 +- .../AuthenticationTests.cs | 230 +++++++++++++++++- .../AuthenticationTests.cs | 37 ++- 10 files changed, 453 insertions(+), 46 deletions(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs new file mode 100644 index 0000000000..a6a8afe19f --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNet.HttpFeature.Security; +using Microsoft.Net.Server; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class AuthenticationHandler : IAuthenticationHandler + { + private RequestContext _requestContext; + private AuthenticationTypes _authTypes; + private AuthenticationTypes _customChallenges; + + internal AuthenticationHandler(RequestContext requestContext) + { + _requestContext = requestContext; + _authTypes = requestContext.AuthenticationChallenges; + _customChallenges = AuthenticationTypes.None; + } + + public void Authenticate(IAuthenticateContext context) + { + var user = _requestContext.User; + var identity = user == null ? null : (ClaimsIdentity)user.Identity; + + foreach (var authType in ListEnabledAuthTypes()) + { + string authString = authType.ToString(); + if (context.AuthenticationTypes.Contains(authString, StringComparer.Ordinal)) + { + if (identity != null && identity.IsAuthenticated + && string.Equals(authString, identity.AuthenticationType, StringComparison.Ordinal)) + { + context.Authenticated((ClaimsIdentity)user.Identity, properties: null, description: GetDescription(user.Identity.AuthenticationType)); + } + else + { + context.NotAuthenticated(authString, properties: null, description: GetDescription(user.Identity.AuthenticationType)); + } + } + } + } + + public Task AuthenticateAsync(IAuthenticateContext context) + { + Authenticate(context); + return Task.FromResult(0); + } + + public void Challenge(IChallengeContext context) + { + foreach (var authType in ListEnabledAuthTypes()) + { + var authString = authType.ToString(); + // Not including any auth types means it's a blanket challenge for any auth type. + if (context.AuthenticationTypes == null || context.AuthenticationTypes.Count == 0 + || context.AuthenticationTypes.Contains(authString, StringComparer.Ordinal)) + { + _customChallenges |= authType; + context.Accept(authString, GetDescription(authType.ToString())); + } + } + // A challenge was issued, it overrides any pre-set auth types. + _requestContext.AuthenticationChallenges = _customChallenges; + } + + public void GetDescriptions(IAuthTypeContext context) + { + // TODO: Caching, this data doesn't change per request. + foreach (var authType in ListEnabledAuthTypes()) + { + context.Accept(GetDescription(authType.ToString())); + } + } + + public void SignIn(ISignInContext context) + { + // Not supported + } + + public void SignOut(ISignOutContext context) + { + // Not supported + } + + private IDictionary GetDescription(string authenticationType) + { + return new Dictionary() + { + { "AuthenticationType", authenticationType }, + { "Caption", "Windows:" + authenticationType }, + }; + } + + private IEnumerable ListEnabledAuthTypes() + { + // Order by strength. + if ((_authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos) + { + yield return AuthenticationTypes.Kerberos; + } + if ((_authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate) + { + yield return AuthenticationTypes.Negotiate; + } + if ((_authTypes & AuthenticationTypes.NTLM) == AuthenticationTypes.NTLM) + { + yield return AuthenticationTypes.NTLM; + } + /*if ((_authTypes & AuthenticationTypes.Digest) == AuthenticationTypes.Digest) + { + // TODO: + throw new NotImplementedException("Digest challenge generation has not been implemented."); + yield return AuthenticationTypes.Digest; + }*/ + if ((_authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic) + { + yield return AuthenticationTypes.Basic; + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index f1876bcf89..f028582f03 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -70,6 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener { _requestContext = requestContext; _features = new FeatureCollection(); + _authHandler = new AuthenticationHandler(requestContext); PopulateFeatures(); } @@ -109,14 +110,11 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpWebSocketFeature), this); } - // TODO: - // _environment.CallCancelled = _cts.Token; - // _environment.User = _request.User; - // Channel binding - + // TODO: /* - // Server + Server _environment.Listener = _server; + Channel binding _environment.ConnectionId = _request.ConnectionId; */ } diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj index 1b81c12fac..e4001830ea 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -21,6 +21,7 @@ + diff --git a/src/Microsoft.Net.Server/AuthenticationManager.cs b/src/Microsoft.Net.Server/AuthenticationManager.cs index 64ee0b4d7d..e7b1ab6e71 100644 --- a/src/Microsoft.Net.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Server/AuthenticationManager.cs @@ -65,6 +65,10 @@ namespace Microsoft.Net.Server } set { + if (_authTypes == AuthenticationTypes.None) + { + throw new ArgumentException("value", "'None' is not a valid authentication type. Use 'AllowAnonymous' instead."); + } _authTypes = value; SetServerSecurity(); } @@ -106,22 +110,25 @@ namespace Microsoft.Net.Server } } - // TODO: If we're not going to support Digest then this whole list can be pre-computed and cached. - // consider even pre-serialzing and caching the bytes for the !AllowAnonymous scenario. - internal IList GenerateChallenges() + internal static IList GenerateChallenges(AuthenticationTypes authTypes) { IList challenges = new List(); + if (authTypes == AuthenticationTypes.None) + { + return challenges; + } + // Order by strength. - if ((_authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos) + if ((authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos) { challenges.Add("Kerberos"); } - if ((_authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate) + if ((authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate) { challenges.Add("Negotiate"); } - if ((_authTypes & AuthenticationTypes.Ntlm) == AuthenticationTypes.Ntlm) + if ((authTypes & AuthenticationTypes.NTLM) == AuthenticationTypes.NTLM) { challenges.Add("NTLM"); } @@ -131,7 +138,7 @@ namespace Microsoft.Net.Server throw new NotImplementedException("Digest challenge generation has not been implemented."); // challenges.Add("Digest"); }*/ - if ((_authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic) + if ((authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic) { // TODO: Realm challenges.Add("Basic"); @@ -139,9 +146,9 @@ namespace Microsoft.Net.Server return challenges; } - internal void SetAuthenticationChallenge(Response response) + internal void SetAuthenticationChallenge(RequestContext context) { - IList challenges = GenerateChallenges(); + IList challenges = GenerateChallenges(context.AuthenticationChallenges); if (challenges.Count > 0) { @@ -149,7 +156,7 @@ namespace Microsoft.Net.Server // Append to the existing header, if any. Some clients (IE, Chrome) require each challenges to be sent on their own line/header. string[] oldValues; string[] newValues; - if (response.Headers.TryGetValue(HttpKnownHeaderNames.WWWAuthenticate, out oldValues)) + if (context.Response.Headers.TryGetValue(HttpKnownHeaderNames.WWWAuthenticate, out oldValues)) { newValues = new string[oldValues.Length + challenges.Count]; Array.Copy(oldValues, newValues, oldValues.Length); @@ -160,7 +167,7 @@ namespace Microsoft.Net.Server newValues = new string[challenges.Count]; challenges.CopyTo(newValues, 0); } - response.Headers[HttpKnownHeaderNames.WWWAuthenticate] = newValues; + context.Response.Headers[HttpKnownHeaderNames.WWWAuthenticate] = newValues; } } @@ -184,10 +191,30 @@ namespace Microsoft.Net.Server && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { #if NET45 - return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken)); + return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken, + GetAuthTypeFromRequest(requestInfo->pInfo->AuthType).ToString())); #endif } - return new ClaimsPrincipal(new ClaimsIdentity(string.Empty)); // Anonymous / !IsAuthenticated + return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated + } + + private static AuthenticationTypes GetAuthTypeFromRequest(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE input) + { + switch (input) + { + case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic: + return AuthenticationTypes.Basic; + // case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest: + // return AuthenticationTypes.Digest; + case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM: + return AuthenticationTypes.NTLM; + case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate: + return AuthenticationTypes.Negotiate; + case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos: + return AuthenticationTypes.Kerberos; + default: + throw new NotImplementedException(input.ToString()); + } } } } diff --git a/src/Microsoft.Net.Server/AuthenticationTypes.cs b/src/Microsoft.Net.Server/AuthenticationTypes.cs index e524d6b69c..9906ba2053 100644 --- a/src/Microsoft.Net.Server/AuthenticationTypes.cs +++ b/src/Microsoft.Net.Server/AuthenticationTypes.cs @@ -22,10 +22,10 @@ namespace Microsoft.Net.Server [Flags] public enum AuthenticationTypes { - // None = 0x0, // None is invalid, use AllowAnonymous (which must have a non-zero value). + None = 0x0, Basic = 0x1, // Digest = 0x2, // TODO: Verify this is no longer supported by Http.Sys - Ntlm = 0x4, + NTLM = 0x4, Negotiate = 0x8, Kerberos = 0x10, AllowAnonymous = 0x1000 diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index e0cc636bd1..3864652cef 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -45,14 +45,15 @@ namespace Microsoft.Net.Server private CancellationTokenSource _requestAbortSource; private CancellationToken? _disconnectToken; - internal RequestContext(WebListener httpListener, NativeRequestContext memoryBlob) + internal RequestContext(WebListener server, NativeRequestContext memoryBlob) { // TODO: Verbose log - _server = httpListener; + _server = server; _memoryBlob = memoryBlob; _request = new Request(this, _memoryBlob); _response = new Response(this); _request.ReleasePins(); + AuthenticationChallenges = server.AuthenticationManager.AuthenticationTypes & ~AuthenticationTypes.AllowAnonymous; } public Request Request @@ -129,6 +130,12 @@ namespace Microsoft.Net.Server } } + /// + /// The authentication challengest that will be added to the response if the status code is 401. + /// This must be a subset of the AuthenticationTypes enabled on the server. + /// + public AuthenticationTypes AuthenticationChallenges { get; set; } + public bool IsUpgradableRequest { get { return _request.IsUpgradable; } diff --git a/src/Microsoft.Net.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Server/RequestProcessing/Response.cs index 0bca230c20..d803bb4a23 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Response.cs @@ -471,7 +471,7 @@ namespace Microsoft.Net.Server // 401 if (StatusCode == (ushort)HttpStatusCode.Unauthorized) { - RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(this); + RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(RequestContext); } UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; diff --git a/src/Microsoft.Net.Server/WebListener.cs b/src/Microsoft.Net.Server/WebListener.cs index a66dd103f8..66a38efdfc 100644 --- a/src/Microsoft.Net.Server/WebListener.cs +++ b/src/Microsoft.Net.Server/WebListener.cs @@ -661,7 +661,8 @@ namespace Microsoft.Net.Server var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob; if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) { - SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, AuthenticationManager.GenerateChallenges()); + SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, + AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationTypes)); return false; } return true; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index eae1a1e89e..db7417482d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -16,6 +16,7 @@ // permissions and limitations under the License. using System; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -31,12 +32,13 @@ namespace Microsoft.AspNet.Server.WebListener private const string Address = "http://localhost:8080/"; [Theory] + [InlineData(AuthenticationTypes.AllowAnonymous)] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] [InlineData(AuthenticationTypes.Basic)] - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType) { using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => @@ -56,7 +58,7 @@ namespace Microsoft.AspNet.Server.WebListener [Theory] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented [InlineData(AuthenticationTypes.Basic)] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType) @@ -75,7 +77,7 @@ namespace Microsoft.AspNet.Server.WebListener [Theory] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented [InlineData(AuthenticationTypes.Basic)] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType) @@ -101,7 +103,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateAuthServer( AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate - | AuthenticationTypes.Ntlm + | AuthenticationTypes.NTLM /* | AuthenticationTypes.Digest TODO: Not implemented */ | AuthenticationTypes.Basic | AuthenticationTypes.AllowAnonymous, @@ -123,10 +125,10 @@ namespace Microsoft.AspNet.Server.WebListener [Theory] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType) { int requestId = 0; @@ -159,10 +161,10 @@ namespace Microsoft.AspNet.Server.WebListener [Theory] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType) { using (Utilities.CreateAuthServer(authType, env => @@ -178,6 +180,216 @@ namespace Microsoft.AspNet.Server.WebListener } } + [Theory] + [InlineData(AuthenticationTypes.AllowAnonymous)] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.NTLM)] + // [InlineData(AuthenticationTypes.Digest)] + [InlineData(AuthenticationTypes.Basic)] + // [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_GetSingleDescriptions(AuthenticationTypes authType) + { + using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + var resultList = context.GetAuthenticationTypes(); + if (authType == AuthenticationTypes.AllowAnonymous) + { + Assert.Equal(0, resultList.Count()); + } + else + { + Assert.Equal(1, resultList.Count()); + var result = resultList.First(); + Assert.Equal(authType.ToString(), result.AuthenticationType); + Assert.Equal("Windows:" + authType.ToString(), result.Caption); + } + + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + } + } + + [Fact] + public async Task AuthTypes_GetMultipleDescriptions() + { + AuthenticationTypes authType = + AuthenticationTypes.Kerberos + | AuthenticationTypes.Negotiate + | AuthenticationTypes.NTLM + | /*AuthenticationTypes.Digest + |*/ AuthenticationTypes.Basic; + using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + var resultList = context.GetAuthenticationTypes(); + Assert.Equal(4, resultList.Count()); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.NTLM)] + // [InlineData(AuthenticationTypes.Digest)] + [InlineData(AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationTypes authType) + { + var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + var authResults = context.Authenticate(authTypeList); + Assert.False(authResults.Any()); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.NTLM)] + // [InlineData(AuthenticationTypes.Digest)] + // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationTypes authType) + { + var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + using (Utilities.CreateAuthServer(authType, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + var authResults = context.Authenticate(authTypeList); + Assert.Equal(1, authResults.Count()); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address, useDefaultCredentials: true); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.NTLM)] + // [InlineData(AuthenticationTypes.Digest)] + [InlineData(AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationTypes authType) + { + var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + context.Response.Challenge(); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.NTLM)] + // [InlineData(AuthenticationTypes.Digest)] + [InlineData(AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationTypes authType) + { + var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + context.Response.Challenge(authTypeList); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.NTLM)] + // [InlineData(AuthenticationTypes.Digest)] + [InlineData(AuthenticationTypes.Basic)] + public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationTypes authType) + { + var authTypes = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic; + using (Utilities.CreateAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + context.Response.Challenge(authType.ToString()); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(1, response.Headers.WwwAuthenticate.Count); + Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.First().Scheme); + } + } + + [Theory] + [InlineData(AuthenticationTypes.Kerberos)] + [InlineData(AuthenticationTypes.Negotiate)] + [InlineData(AuthenticationTypes.NTLM)] + // [InlineData(AuthenticationTypes.Digest)] + [InlineData(AuthenticationTypes.Basic)] + public async Task AuthTypes_ChallengeDisabledAuthType_Error(AuthenticationTypes authType) + { + var authTypes = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic; + authTypes = authTypes & ~authType; + var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + using (Utilities.CreateAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + Assert.Throws(() => context.Response.Challenge(authType.ToString())); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(Address); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + } + } + private async Task SendRequestAsync(string uri, bool useDefaultCredentials = false) { HttpClientHandler handler = new HttpClientHandler(); diff --git a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs index ce57a86d35..503b515b7e 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs @@ -16,10 +16,10 @@ namespace Microsoft.Net.Server [InlineData(AuthenticationTypes.AllowAnonymous)] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] [InlineData(AuthenticationTypes.Basic)] - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType) { using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) @@ -29,6 +29,14 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); + if (authType == AuthenticationTypes.AllowAnonymous) + { + Assert.Equal(AuthenticationTypes.None, context.AuthenticationChallenges); + } + else + { + Assert.Equal(authType, context.AuthenticationChallenges); + } context.Dispose(); var response = await responseTask; @@ -40,7 +48,7 @@ namespace Microsoft.Net.Server [Theory] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented [InlineData(AuthenticationTypes.Basic)] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType) @@ -60,7 +68,7 @@ namespace Microsoft.Net.Server [Theory] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented [InlineData(AuthenticationTypes.Basic)] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType) @@ -72,6 +80,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); + Assert.Equal(authType, context.AuthenticationChallenges); context.Response.StatusCode = 401; context.Dispose(); @@ -84,19 +93,20 @@ namespace Microsoft.Net.Server [Fact] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { - using (var server = Utilities.CreateAuthServer( + AuthenticationTypes authType = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate - | AuthenticationTypes.Ntlm + | AuthenticationTypes.NTLM /* | AuthenticationTypes.Digest TODO: Not implemented */ - | AuthenticationTypes.Basic - | AuthenticationTypes.AllowAnonymous)) + | AuthenticationTypes.Basic; + using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) { Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); + Assert.Equal(authType, context.AuthenticationChallenges); context.Response.StatusCode = 401; context.Dispose(); @@ -109,10 +119,10 @@ namespace Microsoft.Net.Server [Theory] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType) { using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) @@ -122,12 +132,14 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); + Assert.Equal(authType, context.AuthenticationChallenges); context.Response.StatusCode = 401; context.Dispose(); context = await server.GetContextAsync(); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); + Assert.Equal(authType, context.AuthenticationChallenges); context.Dispose(); var response = await responseTask; @@ -138,10 +150,10 @@ namespace Microsoft.Net.Server [Theory] [InlineData(AuthenticationTypes.Kerberos)] [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.Ntlm)] + [InlineData(AuthenticationTypes.NTLM)] // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] + [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType) { using (var server = Utilities.CreateAuthServer(authType)) @@ -151,6 +163,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); + Assert.Equal(authType, context.AuthenticationChallenges); context.Dispose(); var response = await responseTask; From 136811e7329787b85cc397029d2beb5eb29e9c2a Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 24 Jun 2014 10:18:05 -0700 Subject: [PATCH 080/597] Make IServerFactory AssemblyNeutral. --- .../IServerFactory.cs | 32 +++++++++++++++++++ .../Microsoft.AspNet.Server.WebListener.kproj | 1 + .../project.json | 1 - 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/IServerFactory.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/IServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/IServerFactory.cs new file mode 100644 index 0000000000..0b75dbe5e9 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/IServerFactory.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.Framework.ConfigurationModel; +using Microsoft.Framework.Runtime; + +namespace Microsoft.AspNet.Hosting.Server +{ + [AssemblyNeutral] + public interface IServerFactory + { + IServerInformation Initialize(IConfiguration configuration); + IDisposable Start(IServerInformation serverInformation, Func application); + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj index e4001830ea..b3e1459db4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -24,6 +24,7 @@ + diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index f28e0e19e3..28f41ada38 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNet.FeatureModel": "1.0.0-*", - "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.HttpFeature": "1.0.0-*", "Microsoft.Framework.ConfigurationModel": "1.0.0-*", From 872f18b63be634d9a11e99552c027a54beaa8727 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 24 Jun 2014 10:18:33 -0700 Subject: [PATCH 081/597] Update Claims dependency to 1.0.0-*. --- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Server/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 28f41ada38..80244672cb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -32,7 +32,7 @@ "System.Runtime.Extensions": "4.0.10.0", "System.Runtime.Handles": "4.0.0.0", "System.Runtime.InteropServices": "4.0.20.0", - "System.Security.Claims": "0.1-alpha-*", + "System.Security.Claims": "1.0.0-*", "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Server/project.json index ef68434d86..2a43266d51 100644 --- a/src/Microsoft.Net.Server/project.json +++ b/src/Microsoft.Net.Server/project.json @@ -29,7 +29,7 @@ "System.Runtime.Extensions": "4.0.10.0", "System.Runtime.Handles": "4.0.0.0", "System.Runtime.InteropServices": "4.0.20.0", - "System.Security.Claims": "0.1-alpha-*", + "System.Security.Claims": "1.0.0-*", "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", From 1a579aba01907b31b66663a0018fa85c0f2fee4a Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 1 Jul 2014 15:13:48 -0700 Subject: [PATCH 082/597] Add missing using. --- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 1 - src/Microsoft.Net.Server/RequestProcessing/Request.cs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index f028582f03..f0478cc88d 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -422,7 +422,6 @@ namespace Microsoft.AspNet.Server.WebListener set { _user = value; } } - // TODO: Hook this server up as the default handler, have it issue challenges for configured auth types by name. IAuthenticationHandler IHttpAuthenticationFeature.Handler { get { return _authHandler; } diff --git a/src/Microsoft.Net.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Server/RequestProcessing/Request.cs index 513f5a4f39..40bb8318bf 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Request.cs @@ -32,6 +32,7 @@ using System.Security.Cryptography.X509Certificates; #if NET45 using System.Security.Principal; #endif +using System.Threading; using System.Threading.Tasks; namespace Microsoft.Net.Server From 81c967dfa4699b1da381b37d64cc9e704f27ec21 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 2 Jul 2014 09:04:48 -0700 Subject: [PATCH 083/597] Rename OnRequestAborted to RequestAborted. --- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 2 +- .../ServerTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index f0478cc88d..4f9777011b 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -370,7 +370,7 @@ namespace Microsoft.AspNet.Server.WebListener return Response.SendFileAsync(path, offset, length, cancellation); } - CancellationToken IHttpRequestLifetimeFeature.OnRequestAborted + CancellationToken IHttpRequestLifetimeFeature.RequestAborted { get { return _requestContext.DisconnectToken; } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 0b84f3a63a..3a386c2258 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -194,7 +194,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - CancellationToken ct = httpContext.OnRequestAborted; + CancellationToken ct = httpContext.RequestAborted; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); ct.Register(() => canceled.Set()); @@ -228,7 +228,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - CancellationToken ct = httpContext.OnRequestAborted; + CancellationToken ct = httpContext.RequestAborted; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); ct.Register(() => canceled.Set()); From fe0e5be913e49258f5f898f55781a9c2fb0d37e9 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 3 Jul 2014 10:06:24 -0700 Subject: [PATCH 084/597] Fix IList to IEnumerable change. --- .../AuthenticationHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index a6a8afe19f..e86419c1c5 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Server.WebListener private AuthenticationTypes _customChallenges; internal AuthenticationHandler(RequestContext requestContext) - { + { _requestContext = requestContext; _authTypes = requestContext.AuthenticationChallenges; _customChallenges = AuthenticationTypes.None; @@ -79,7 +79,7 @@ namespace Microsoft.AspNet.Server.WebListener { var authString = authType.ToString(); // Not including any auth types means it's a blanket challenge for any auth type. - if (context.AuthenticationTypes == null || context.AuthenticationTypes.Count == 0 + if (context.AuthenticationTypes == null || !context.AuthenticationTypes.Any() || context.AuthenticationTypes.Contains(authString, StringComparer.Ordinal)) { _customChallenges |= authType; From 112e3e53587bef96e14765c58d1df17e2924485c Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 3 Jul 2014 14:03:57 -0700 Subject: [PATCH 085/597] Rename IHttpOpaqueUpgradeFeature to IHttpUpgradeFeature. --- .../FeatureContext.cs | 8 ++++---- .../OpaqueUpgradeTests.cs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 4f9777011b..9a5023f9b2 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Server.WebListener IHttpRequestLifetimeFeature, IHttpWebSocketFeature, IHttpAuthenticationFeature, - IHttpOpaqueUpgradeFeature + IHttpUpgradeFeature { private RequestContext _requestContext; private FeatureCollection _features; @@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Server.WebListener // Win8+ if (WebSocketHelpers.AreWebSocketsSupported) { - _features.Add(typeof(IHttpOpaqueUpgradeFeature), this); + _features.Add(typeof(IHttpUpgradeFeature), this); _features.Add(typeof(IHttpWebSocketFeature), this); } @@ -380,12 +380,12 @@ namespace Microsoft.AspNet.Server.WebListener _requestContext.Abort(); } - bool IHttpOpaqueUpgradeFeature.IsUpgradableRequest + bool IHttpUpgradeFeature.IsUpgradableRequest { get { return _requestContext.IsUpgradableRequest; } } - Task IHttpOpaqueUpgradeFeature.UpgradeAsync() + Task IHttpUpgradeFeature.UpgradeAsync() { return _requestContext.UpgradeAsync(); } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 6a72bffb2c..48c6e25f1d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.GetFeature(); Assert.NotNull(opaqueFeature); } catch (Exception ex) @@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener await httpContext.Response.WriteAsync("Hello World"); try { - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.GetFeature(); Assert.NotNull(opaqueFeature); await opaqueFeature.UpgradeAsync(); upgradeThrew = false; @@ -97,7 +97,7 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.GetFeature(); Assert.NotNull(opaqueFeature); Assert.True(opaqueFeature.IsUpgradableRequest); await opaqueFeature.UpgradeAsync(); @@ -145,7 +145,7 @@ namespace Microsoft.AspNet.Server.WebListener try { httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.GetFeature(); Assert.NotNull(opaqueFeature); Assert.True(opaqueFeature.IsUpgradableRequest); var opaqueStream = await opaqueFeature.UpgradeAsync(); @@ -186,7 +186,7 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.GetFeature(); Assert.NotNull(opaqueFeature); Assert.False(opaqueFeature.IsUpgradableRequest); } From 1e7da1dc6145b8b5e80c0b206a88dd6f4da98c14 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 7 Jul 2014 12:11:41 -0700 Subject: [PATCH 086/597] Fix versioning for Microsoft.Net.WebSockets --- src/Microsoft.Net.WebSockets/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index e016a4ca4f..5f000445bf 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,5 +1,5 @@ { - "version": "0.1-alpha-*", + "version": "1.0.0-*", "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" }, From 91b61bf6f6a0f6c1acbdf5b63d04da2ada0df0dd Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 8 Jul 2014 10:11:25 -0700 Subject: [PATCH 087/597] Add using statement for extension methods. --- .../OpaqueUpgradeTests.cs | 1 + .../ServerTests.cs | 1 + .../WebSocketTests.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 48c6e25f1d..345092d7ff 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -25,6 +25,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http; using Microsoft.AspNet.PipelineCore; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 3a386c2258..23ff1f232a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -25,6 +25,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http; using Microsoft.AspNet.PipelineCore; using Microsoft.Net.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index 1720bddd0a..3b830843d6 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -21,6 +21,7 @@ using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; From bcb816f7d185bbaa9b157d7193d8c04184179b80 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 10 Jul 2014 09:45:36 -0700 Subject: [PATCH 088/597] Fixed if DEBUG --- src/Microsoft.Net.WebSockets/WebSocketBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Net.WebSockets/WebSocketBase.cs b/src/Microsoft.Net.WebSockets/WebSocketBase.cs index fe2ab6d1e2..30c9ebc9d5 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBase.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBase.cs @@ -482,7 +482,7 @@ namespace Microsoft.Net.WebSockets _state = WebSocketState.Aborted; -#if DEBUG +#if DEBUG && NET45 string stackTrace = new StackTrace().ToString(); if (_closeStack == null) { @@ -715,7 +715,7 @@ namespace Microsoft.Net.WebSockets _state = WebSocketState.Closed; -#if DEBUG +#if DEBUG && NET45 if (_closeStack == null) { _closeStack = new StackTrace().ToString(); From b2d2840a6f3958ade5d77d2b6dd78df4d13a8881 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 13 Jul 2014 22:09:09 -0700 Subject: [PATCH 089/597] Renamed configurations to frameworks in project.json --- samples/HelloWorld/project.json | 4 ++-- samples/SelfHostServer/project.json | 6 +++--- src/Microsoft.AspNet.Security.Windows/project.json | 4 ++-- src/Microsoft.AspNet.Server.WebListener/project.json | 4 ++-- src/Microsoft.Net.Server/project.json | 6 +++--- src/Microsoft.Net.WebSockets/project.json | 4 ++-- test/Microsoft.AspNet.Security.Windows.Test/project.json | 4 ++-- .../project.json | 4 ++-- test/Microsoft.Net.Server.FunctionalTests/project.json | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index e711f3f228..4c1c40e709 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,8 +1,8 @@ -{ +{ "dependencies": { "Microsoft.Net.Server" : "" }, - "configurations": { + "frameworks": { "net45": { }, "k10" : { "dependencies": { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index fe75325e0a..527118090a 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,4 +1,4 @@ -{ +{ "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", @@ -6,7 +6,7 @@ "Microsoft.Net.Server": "" }, "commands": { "web": "Microsoft.AspNet.Hosting --server=Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:8080" }, - "configurations": { + "frameworks": { "net45": { }, "k10": { @@ -28,4 +28,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNet.Security.Windows/project.json b/src/Microsoft.AspNet.Security.Windows/project.json index 555d2501cd..d2e616766c 100644 --- a/src/Microsoft.AspNet.Security.Windows/project.json +++ b/src/Microsoft.AspNet.Security.Windows/project.json @@ -1,9 +1,9 @@ -{ +{ "version": "1.0.0-*", "dependencies": { }, "compilationOptions" : { "allowUnsafe": true }, - "configurations": + "frameworks": { "net45" : { "dependencies": { diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 80244672cb..59e324ab0c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -12,7 +12,7 @@ "compilationOptions": { "allowUnsafe": true }, - "configurations": { + "frameworks": { "net45": {}, "k10": { "dependencies": { @@ -44,4 +44,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Server/project.json index 2a43266d51..cfa86d9665 100644 --- a/src/Microsoft.Net.Server/project.json +++ b/src/Microsoft.Net.Server/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "dependencies": { "Microsoft.Framework.Logging": "1.0.0-*", @@ -7,7 +7,7 @@ "compilationOptions": { "allowUnsafe": true }, - "configurations": { + "frameworks": { "net45": {}, "k10": { "dependencies": { @@ -41,4 +41,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 5f000445bf..0200c4e41c 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,10 +1,10 @@ -{ +{ "version": "1.0.0-*", "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" }, "compilationOptions" : { "allowUnsafe": true }, - "configurations": { + "frameworks": { "net45" : { }, "k10" : { "dependencies": { diff --git a/test/Microsoft.AspNet.Security.Windows.Test/project.json b/test/Microsoft.AspNet.Security.Windows.Test/project.json index 0b61c27922..841fe8d67c 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/project.json +++ b/test/Microsoft.AspNet.Security.Windows.Test/project.json @@ -1,4 +1,4 @@ -{ +{ "dependencies": { "Microsoft.AspNet.Security.Windows" : "", "Microsoft.AspNet.Server.WebListener" : "", @@ -7,7 +7,7 @@ "xunit.core": "2.0.0-aspnet-*", "xunit.execution": "2.0.0-aspnet-*" }, - "configurations": { + "frameworks": { "net45": { "dependencies": { "System.Net.Http": "", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 36e6168fc9..e93d53e995 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,4 +1,4 @@ -{ +{ "commands": { "test": "Xunit.KRunner" }, @@ -14,7 +14,7 @@ "Microsoft.Net.Server" : "", "Xunit.KRunner": "1.0.0-*" }, - "configurations": { + "frameworks": { "net45": { "dependencies": { "System.Net.Http": "", diff --git a/test/Microsoft.Net.Server.FunctionalTests/project.json b/test/Microsoft.Net.Server.FunctionalTests/project.json index e070fa1cc7..1c3855abb0 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Server.FunctionalTests/project.json @@ -1,4 +1,4 @@ -{ +{ "commands": { "test": "Xunit.KRunner" }, @@ -6,7 +6,7 @@ "Microsoft.Net.Server" : "", "Xunit.KRunner": "1.0.0-*" }, - "configurations": { + "frameworks": { "net45": { "dependencies": { "System.Net.Http": "", From 4bbdefbe65a11ef898f7b5d45743f83af3d2d800 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 14 Jul 2014 16:26:28 -0700 Subject: [PATCH 090/597] Reacting to System.Collections versioning change --- samples/HelloWorld/project.json | 4 ++-- samples/SelfHostServer/project.json | 4 ++-- src/Microsoft.AspNet.Server.WebListener/project.json | 4 ++-- src/Microsoft.Net.Server/project.json | 4 ++-- src/Microsoft.Net.WebSockets/project.json | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 4c1c40e709..8bf9217d36 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,4 +1,4 @@ -{ +{ "dependencies": { "Microsoft.Net.Server" : "" }, @@ -6,7 +6,7 @@ "net45": { }, "k10" : { "dependencies": { - "System.Collections": "4.0.0.0", + "System.Collections": "4.0.10.0", "System.Console" : "4.0.0.0", "System.Globalization": "4.0.10.0", "System.IO" : "4.0.0.0", diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 527118090a..bee846ffc4 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,4 +1,4 @@ -{ +{ "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", @@ -11,7 +11,7 @@ }, "k10": { "dependencies": { - "System.Collections": "4.0.0.0", + "System.Collections": "4.0.10.0", "System.Console": "4.0.0.0", "System.Diagnostics.Debug": "4.0.10.0", "System.Diagnostics.Tools": "4.0.0.0", diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 59e324ab0c..d7c511301b 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNet.FeatureModel": "1.0.0-*", @@ -17,7 +17,7 @@ "k10": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.0.0", + "System.Collections": "4.0.10.0", "System.Collections.Concurrent": "4.0.0.0", "System.Diagnostics.Contracts": "4.0.0.0", "System.Diagnostics.Debug": "4.0.10.0", diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Server/project.json index cfa86d9665..1c2d1ea7f0 100644 --- a/src/Microsoft.Net.Server/project.json +++ b/src/Microsoft.Net.Server/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "dependencies": { "Microsoft.Framework.Logging": "1.0.0-*", @@ -13,7 +13,7 @@ "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.0.0", + "System.Collections": "4.0.10.0", "System.Collections.Concurrent": "4.0.0.0", "System.Diagnostics.Contracts": "4.0.0.0", "System.Diagnostics.Debug": "4.0.10.0", diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 0200c4e41c..d1271a020f 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" @@ -9,7 +9,7 @@ "k10" : { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.0.0", + "System.Collections": "4.0.10.0", "System.Collections.Concurrent": "4.0.0.0", "System.Diagnostics.Contracts": "4.0.0.0", "System.Diagnostics.Debug": "4.0.10.0", From 09267cca2fe53d9ae28484f8b1d7be8b64640b5b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 17 Jul 2014 09:44:03 -0700 Subject: [PATCH 091/597] Reacting to System.Security.Cryptography.Encryption package rename --- src/Microsoft.Net.WebSockets/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index d1271a020f..1a18c457ba 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -24,7 +24,7 @@ "System.Runtime.Extensions": "4.0.10.0", "System.Runtime.Handles": "4.0.0.0", "System.Runtime.InteropServices": "4.0.20.0", - "System.Security.Cryptography": "4.0.0.0", + "System.Security.Cryptography.Encryption": "4.0.0.0", "System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0", "System.Security.Principal": "4.0.0.0", "System.Text.Encoding": "4.0.20.0", From 53e38e2a23afd21dce7fc8d3605fe7c2804560b4 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 10 Jul 2014 12:02:53 -0700 Subject: [PATCH 092/597] #45 Add friendly header collection APIs for people using WebListener directly. --- samples/HelloWorld/Program.cs | 2 +- .../AuthenticationManager.cs | 18 +- .../DictionaryExtensions.cs | 68 ------- .../Microsoft.Net.Server.kproj | 3 +- .../NativeInterop/UnsafeNativeMethods.cs | 6 +- .../RequestProcessing/HeaderCollection.cs | 183 ++++++++++++++++++ .../RequestProcessing/HeaderParser.cs | 58 ++++++ .../RequestProcessing/Request.cs | 17 +- .../RequestProcessing/RequestContext.cs | 35 ++-- .../RequestProcessing/RequestHeaders.cs | 28 +-- .../RequestProcessing/Response.cs | 28 +-- .../WebSocketHelpers.cs | 14 +- .../OpaqueUpgradeTests.cs | 6 +- .../RequestHeaderTests.cs | 18 +- .../ResponseBodyTests.cs | 10 +- .../ResponseHeaderTests.cs | 20 +- .../ResponseSendFileTests.cs | 12 +- 17 files changed, 330 insertions(+), 196 deletions(-) delete mode 100644 src/Microsoft.Net.Server/DictionaryExtensions.cs create mode 100644 src/Microsoft.Net.Server/RequestProcessing/HeaderCollection.cs create mode 100644 src/Microsoft.Net.Server/RequestProcessing/HeaderParser.cs diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 3eb30c4f7e..243af9a49d 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -48,7 +48,7 @@ namespace HelloWorld // Request // context.Request.ProtocolVersion // context.Request.IsLocal - // context.Request.Headers // TODO: Header helpers? + // context.Request.Headers // context.Request.Method // context.Request.Body // Content-Length - long? diff --git a/src/Microsoft.Net.Server/AuthenticationManager.cs b/src/Microsoft.Net.Server/AuthenticationManager.cs index e7b1ab6e71..458b46261d 100644 --- a/src/Microsoft.Net.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Server/AuthenticationManager.cs @@ -24,6 +24,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Principal; @@ -152,22 +153,7 @@ namespace Microsoft.Net.Server if (challenges.Count > 0) { - // TODO: We need a better header API that just lets us append values. - // Append to the existing header, if any. Some clients (IE, Chrome) require each challenges to be sent on their own line/header. - string[] oldValues; - string[] newValues; - if (context.Response.Headers.TryGetValue(HttpKnownHeaderNames.WWWAuthenticate, out oldValues)) - { - newValues = new string[oldValues.Length + challenges.Count]; - Array.Copy(oldValues, newValues, oldValues.Length); - challenges.CopyTo(newValues, oldValues.Length); - } - else - { - newValues = new string[challenges.Count]; - challenges.CopyTo(newValues, 0); - } - context.Response.Headers[HttpKnownHeaderNames.WWWAuthenticate] = newValues; + context.Response.Headers.AppendValues(HttpKnownHeaderNames.WWWAuthenticate, challenges.ToArray()); } } diff --git a/src/Microsoft.Net.Server/DictionaryExtensions.cs b/src/Microsoft.Net.Server/DictionaryExtensions.cs deleted file mode 100644 index 7aa0e65d2c..0000000000 --- a/src/Microsoft.Net.Server/DictionaryExtensions.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Linq; -using System.Text; - -namespace System.Collections.Generic -{ - internal static class DictionaryExtensions - { - internal static void Append(this IDictionary dictionary, string key, string value) - { - string[] orriginalValues; - if (dictionary.TryGetValue(key, out orriginalValues)) - { - string[] newValues = new string[orriginalValues.Length + 1]; - orriginalValues.CopyTo(newValues, 0); - newValues[newValues.Length - 1] = value; - dictionary[key] = newValues; - } - else - { - dictionary[key] = new string[] { value }; - } - } - - internal static string Get(this IDictionary dictionary, string key) - { - string[] values; - if (dictionary.TryGetValue(key, out values)) - { - return string.Join(", ", values); - } - return null; - } - - internal static T Get(this IDictionary dictionary, string key, T fallback = default(T)) - { - object values; - if (dictionary.TryGetValue(key, out values)) - { - return (T)values; - } - return fallback; - } - } -} diff --git a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj index 7c64fe5b48..7ef3155968 100644 --- a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj +++ b/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj @@ -22,7 +22,6 @@ - @@ -52,6 +51,8 @@ + + diff --git a/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs index 096887987f..acf409ed44 100644 --- a/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs @@ -961,9 +961,9 @@ namespace Microsoft.Net.Server { headerValue = string.Empty; } - // Note that Http.Sys currently collapses all headers of the same name to a single string, so - // append will just set. - unknownHeaders.Append(headerName, headerValue); + // Note that Http.Sys currently collapses all headers of the same name to a single coma seperated string, + // so we can just call Set. + unknownHeaders[headerName] = new[] { headerValue }; } pUnknownHeader++; } diff --git a/src/Microsoft.Net.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.Net.Server/RequestProcessing/HeaderCollection.cs new file mode 100644 index 0000000000..62a800cd71 --- /dev/null +++ b/src/Microsoft.Net.Server/RequestProcessing/HeaderCollection.cs @@ -0,0 +1,183 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Microsoft.Net.Server +{ + public class HeaderCollection : IDictionary + { + public HeaderCollection() + : this(new Dictionary(4, StringComparer.OrdinalIgnoreCase)) + { + } + + public HeaderCollection(IDictionary store) + { + Store = store; + } + + private IDictionary Store { get; set; } + + public string this[string key] + { + get { return Get(key); } + set + { + if (string.IsNullOrEmpty(value)) + { + Remove(key); + } + else + { + Set(key, value); + } + } + } + + string[] IDictionary.this[string key] + { + get { return Store[key]; } + set { Store[key] = value; } + } + + public int Count + { + get { return Store.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public ICollection Keys + { + get { return Store.Keys; } + } + + public ICollection Values + { + get { return Store.Values; } + } + + public void Add(KeyValuePair item) + { + Store.Add(item); + } + + public void Add(string key, string[] value) + { + Store.Add(key, value); + } + + public void Append(string key, string value) + { + string[] values; + if (Store.TryGetValue(key, out values)) + { + var newValues = new string[values.Length + 1]; + Array.Copy(values, newValues, values.Length); + newValues[values.Length] = value; + Store[key] = newValues; + } + else + { + Set(key, value); + } + } + + public void AppendValues(string key, params string[] values) + { + string[] oldValues; + if (Store.TryGetValue(key, out oldValues)) + { + var newValues = new string[oldValues.Length + values.Length]; + Array.Copy(oldValues, newValues, oldValues.Length); + Array.Copy(values, 0, newValues, oldValues.Length, values.Length); + Store[key] = newValues; + } + else + { + SetValues(key, values); + } + } + + public void Clear() + { + Store.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return Store.Contains(item); + } + + public bool ContainsKey(string key) + { + return Store.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + Store.CopyTo(array, arrayIndex); + } + + public string Get(string key) + { + string[] values; + if (Store.TryGetValue(key, out values)) + { + return string.Join(", ", values); + } + return null; + } + + public IEnumerator> GetEnumerator() + { + return Store.GetEnumerator(); + } + + public IEnumerable GetValues(string key) + { + string[] values; + if (Store.TryGetValue(key, out values)) + { + return HeaderParser.SplitValues(values); + } + return HeaderParser.Empty; + } + + public bool Remove(KeyValuePair item) + { + return Store.Remove(item); + } + + public bool Remove(string key) + { + return Store.Remove(key); + } + + public void Set(string key, string value) + { + Store[key] = new[] { value }; + } + + public void SetValues(string key, params string[] values) + { + Store[key] = values; + } + + public bool TryGetValue(string key, out string[] value) + { + return Store.TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Net.Server/RequestProcessing/HeaderParser.cs b/src/Microsoft.Net.Server/RequestProcessing/HeaderParser.cs new file mode 100644 index 0000000000..fb217f06b1 --- /dev/null +++ b/src/Microsoft.Net.Server/RequestProcessing/HeaderParser.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Net.Server +{ + internal static class HeaderParser + { + internal static IEnumerable Empty = new string[0]; + + // Split on commas, except in quotes + internal static IEnumerable SplitValues(string[] values) + { + foreach (var value in values) + { + int start = 0; + bool inQuotes = false; + int current = 0; + for ( ; current < value.Length; current++) + { + char ch = value[current]; + if (inQuotes) + { + if (ch == '"') + { + inQuotes = false; + } + } + else if (ch == '"') + { + inQuotes = true; + } + else if (ch == ',') + { + var subValue = value.Substring(start, current - start); + if (!string.IsNullOrWhiteSpace(subValue)) + { + yield return subValue.Trim(); + start = current + 1; + } + } + } + + if (start < current) + { + var subValue = value.Substring(start, current - start); + if (!string.IsNullOrWhiteSpace(subValue)) + { + yield return subValue.Trim(); + start = current + 1; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Net.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Server/RequestProcessing/Request.cs index 40bb8318bf..4e05202106 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Request.cs @@ -61,7 +61,7 @@ namespace Microsoft.Net.Server private X509Certificate _clientCert; - private IDictionary _headers; + private HeaderCollection _headers; private BoundaryType _contentBoundaryType; private long? _contentLength; private Stream _nativeStream; @@ -140,7 +140,7 @@ namespace Microsoft.Net.Server } _httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, OriginalBlobAddress); - _headers = new RequestHeaders(_nativeRequestContext); + _headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2* requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; _user = AuthenticationManager.GetUser(requestV2->pRequestInfo); @@ -250,7 +250,7 @@ namespace Microsoft.Net.Server } } - public IDictionary Headers + public HeaderCollection Headers { get { return _headers; } } @@ -424,17 +424,6 @@ namespace Microsoft.Net.Server return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress); } - // TODO: We need an easier to user header collection that has this built in - internal string GetHeader(string headerName) - { - string[] values; - if (Headers.TryGetValue(headerName, out values)) - { - return string.Join(", ", values); - } - return string.Empty; - } - // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to // enable this, but it's unclear what Http.Sys would do. diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs index 3864652cef..98b9c99cb6 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs @@ -179,28 +179,28 @@ namespace Microsoft.Net.Server } // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - string connection = Request.GetHeader(HttpKnownHeaderNames.Connection); + string connection = Request.Headers[HttpKnownHeaderNames.Connection] ?? string.Empty; if (connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) { return false; } // Upgrade: websocket - string upgrade = Request.GetHeader(HttpKnownHeaderNames.Upgrade); + string upgrade = Request.Headers[HttpKnownHeaderNames.Upgrade]; if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) { return false; } // Sec-WebSocket-Version: 13 - string version = Request.GetHeader(HttpKnownHeaderNames.SecWebSocketVersion); + string version = Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) { return false; } // Sec-WebSocket-Key: {base64string} - string key = Request.GetHeader(HttpKnownHeaderNames.SecWebSocketKey); + string key = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; if (!WebSocketHelpers.IsValidWebSocketKey(key)) { return false; @@ -229,28 +229,28 @@ namespace Microsoft.Net.Server } // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - string connection = Request.GetHeader(HttpKnownHeaderNames.Connection); + string connection = Request.Headers[HttpKnownHeaderNames.Connection] ?? string.Empty; if (connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) { throw new InvalidOperationException("The Connection header is invalid: " + connection); } // Upgrade: websocket - string upgrade = Request.GetHeader(HttpKnownHeaderNames.Upgrade); + string upgrade = Request.Headers[HttpKnownHeaderNames.Upgrade]; if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The Upgrade header is invalid: " + upgrade); } // Sec-WebSocket-Version: 13 - string version = Request.GetHeader(HttpKnownHeaderNames.SecWebSocketVersion); + string version = Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The Sec-WebSocket-Version header is invalid or not supported: " + version); } // Sec-WebSocket-Key: {base64string} - string key = Request.GetHeader(HttpKnownHeaderNames.SecWebSocketKey); + string key = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; if (!WebSocketHelpers.IsValidWebSocketKey(key)) { throw new InvalidOperationException("The Sec-WebSocket-Key header is invalid: " + upgrade); @@ -317,29 +317,22 @@ namespace Microsoft.Net.Server { try { - // TODO: We need a better header collection API. ValidateWebSocketRequest(); - string subProtocols = string.Empty; - string[] values; - if (Request.Headers.TryGetValue(HttpKnownHeaderNames.SecWebSocketProtocol, out values)) - { - subProtocols = string.Join(", ", values); - } - + var subProtocols = Request.Headers.GetValues(HttpKnownHeaderNames.SecWebSocketProtocol); bool shouldSendSecWebSocketProtocolHeader = WebSocketHelpers.ProcessWebSocketProtocolHeader(subProtocols, subProtocol); if (shouldSendSecWebSocketProtocolHeader) { - Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = new[] { subProtocol }; + Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = subProtocol; } // negotiate the websocket key return value - string secWebSocketKey = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey].First(); + string secWebSocketKey = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); - Response.Headers.Add(HttpKnownHeaderNames.Connection, new[] { HttpKnownHeaderNames.Upgrade }); - Response.Headers.Add(HttpKnownHeaderNames.Upgrade, new[] { WebSocketHelpers.WebSocketUpgradeToken }); - Response.Headers.Add(HttpKnownHeaderNames.SecWebSocketAccept, new[] { secWebSocketAccept }); + Response.Headers.AppendValues(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); + Response.Headers.AppendValues(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); + Response.Headers.AppendValues(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); Stream opaqueStream = await UpgradeAsync(); diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs index 46f432f10b..113f5bc3fd 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs @@ -102,17 +102,27 @@ namespace Microsoft.Net.Server } } - bool IDictionary.ContainsKey(string key) + public bool ContainsKey(string key) { return PropertiesContainsKey(key) || Extra.ContainsKey(key); } - ICollection IDictionary.Keys + public ICollection Keys { get { return PropertiesKeys().Concat(Extra.Keys).ToArray(); } } - bool IDictionary.Remove(string key) + ICollection IDictionary.Values + { + get { return PropertiesValues().Concat(Extra.Values).ToArray(); } + } + + public int Count + { + get { return PropertiesKeys().Count() + Extra.Count; } + } + + public bool Remove(string key) { // Although this is a mutating operation, Extra is used instead of StrongExtra, // because if a real dictionary has not been allocated the default behavior of the @@ -120,16 +130,11 @@ namespace Microsoft.Net.Server return PropertiesTryRemove(key) || Extra.Remove(key); } - bool IDictionary.TryGetValue(string key, out string[] value) + public bool TryGetValue(string key, out string[] value) { return PropertiesTryGetValue(key, out value) || Extra.TryGetValue(key, out value); } - ICollection IDictionary.Values - { - get { return PropertiesValues().Concat(Extra.Values).ToArray(); } - } - void ICollection>.Add(KeyValuePair item) { ((IDictionary)this).Add(item.Key, item.Value); @@ -155,11 +160,6 @@ namespace Microsoft.Net.Server PropertiesEnumerable().Concat(Extra).ToArray().CopyTo(array, arrayIndex); } - int ICollection>.Count - { - get { return PropertiesKeys().Count() + Extra.Count; } - } - bool ICollection>.IsReadOnly { get { return false; } diff --git a/src/Microsoft.Net.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Server/RequestProcessing/Response.cs index d803bb4a23..ec5eeecbf4 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Server/RequestProcessing/Response.cs @@ -38,7 +38,7 @@ namespace Microsoft.Net.Server private static readonly string[] ZeroContentLength = new[] { "0" }; private ResponseState _responseState; - private IDictionary _headers; + private HeaderCollection _headers; private string _reasonPhrase; private ResponseStream _nativeStream; private long _contentLength; @@ -53,7 +53,7 @@ namespace Microsoft.Net.Server // TODO: Verbose log _requestContext = httpContext; _nativeResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2(); - _headers = new Dictionary(StringComparer.OrdinalIgnoreCase); + _headers = new HeaderCollection(); _boundaryType = BoundaryType.None; _nativeResponse.Response_V1.StatusCode = (ushort)HttpStatusCode.OK; _nativeResponse.Response_V1.Version.MajorVersion = 1; @@ -156,17 +156,9 @@ namespace Microsoft.Net.Server return true; } - public IDictionary Headers + public HeaderCollection Headers { get { return _headers; } - set - { - if (value == null) - { - throw new ArgumentNullException("value"); - } - _headers = value; - } } internal long CalculatedLength @@ -214,11 +206,11 @@ namespace Microsoft.Net.Server if (value.Value == 0) { - Headers[HttpKnownHeaderNames.ContentLength] = ZeroContentLength; + ((IDictionary)Headers)[HttpKnownHeaderNames.ContentLength] = ZeroContentLength; } else { - Headers[HttpKnownHeaderNames.ContentLength] = new[] { value.Value.ToString(CultureInfo.InvariantCulture) }; + Headers[HttpKnownHeaderNames.ContentLength] = value.Value.ToString(CultureInfo.InvariantCulture); } } } @@ -239,7 +231,7 @@ namespace Microsoft.Net.Server } else { - Headers[HttpKnownHeaderNames.ContentType] = new[] { value }; + Headers[HttpKnownHeaderNames.ContentType] = value; } } } @@ -535,7 +527,7 @@ namespace Microsoft.Net.Server else if (endOfRequest) { // The request is ending without a body, add a Content-Length: 0 header. - Headers[HttpKnownHeaderNames.ContentLength] = new string[] { "0" }; + Headers[HttpKnownHeaderNames.ContentLength] = "0"; _boundaryType = BoundaryType.ContentLength; _contentLength = 0; flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; @@ -551,7 +543,7 @@ namespace Microsoft.Net.Server } else { - Headers[HttpKnownHeaderNames.TransferEncoding] = new string[] { "chunked" }; + Headers[HttpKnownHeaderNames.TransferEncoding] = "chunked"; _boundaryType = BoundaryType.Chunked; } @@ -561,7 +553,7 @@ namespace Microsoft.Net.Server } else { - Headers[HttpKnownHeaderNames.ContentLength] = new string[] { "0" }; + Headers[HttpKnownHeaderNames.ContentLength] = "0"; _contentLength = 0; _boundaryType = BoundaryType.ContentLength; } @@ -583,7 +575,7 @@ namespace Microsoft.Net.Server { if (Request.ProtocolVersion.Minor == 0 && !keepAliveSet) { - Headers[HttpKnownHeaderNames.KeepAlive] = new string[] { "true" }; + Headers[HttpKnownHeaderNames.KeepAlive] = "true"; } } return flags; diff --git a/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs b/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs index 026f295077..fc8a830408 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs @@ -22,10 +22,12 @@ //------------------------------------------------------------------------------ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.IO; +using System.Linq; using System.Net.WebSockets; using System.Runtime.CompilerServices; using System.Security.Cryptography; @@ -132,9 +134,9 @@ namespace Microsoft.Net.WebSockets } // return value here signifies if a Sec-WebSocket-Protocol header should be returned by the server. - public static bool ProcessWebSocketProtocolHeader(string clientSecWebSocketProtocol, string subProtocol) + public static bool ProcessWebSocketProtocolHeader(IEnumerable clientSecWebSocketProtocols, string subProtocol) { - if (string.IsNullOrEmpty(clientSecWebSocketProtocol)) + if (clientSecWebSocketProtocols == null || !clientSecWebSocketProtocols.Any()) { // client hasn't specified any Sec-WebSocket-Protocol header if (subProtocol != null) @@ -158,14 +160,10 @@ namespace Microsoft.Net.WebSockets // here, we know that the client has specified something, it's not empty // and the server has specified exactly one protocol - string[] requestProtocols = clientSecWebSocketProtocol.Split(new char[] { ',' }, - StringSplitOptions.RemoveEmptyEntries); - // client specified protocols, serverOptions has exactly 1 non-empty entry. Check that // this exists in the list the client specified. - for (int i = 0; i < requestProtocols.Length; i++) + foreach (var currentRequestProtocol in clientSecWebSocketProtocols) { - string currentRequestProtocol = requestProtocols[i].Trim(); if (string.Compare(subProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase) == 0) { return true; @@ -174,7 +172,7 @@ namespace Microsoft.Net.WebSockets throw new WebSocketException(WebSocketError.UnsupportedProtocol, SR.GetString(SR.net_WebSockets_AcceptUnsupportedProtocol, - clientSecWebSocketProtocol, + string.Join(", ", clientSecWebSocketProtocols), subProtocol)); } diff --git a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs index 4b4d82bee6..cbf99ec975 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -25,7 +25,7 @@ namespace Microsoft.Net.Server byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.Body.Write(body, 0, body.Length); - context.Response.Headers["Upgrade"] = new[] { "WebSocket" }; // Win8.1 blocks anything but WebSocket + context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket Assert.ThrowsAsync(async () => await context.UpgradeAsync()); context.Dispose(); HttpResponseMessage response = await clientTask; @@ -44,7 +44,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); Assert.True(context.IsUpgradableRequest); - context.Response.Headers["Upgrade"] = new[] { "WebSocket" }; // Win8.1 blocks anything but WebSocket + context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket Stream serverStream = await context.UpgradeAsync(); Assert.True(serverStream.CanRead); Assert.True(serverStream.CanWrite); @@ -86,7 +86,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); Assert.True(context.IsUpgradableRequest); - context.Response.Headers["Upgrade"] = new[] { "WebSocket" }; // Win8.1 blocks anything but WebSocket + context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket Stream serverStream = await context.UpgradeAsync(); Stream clientStream = await clientTask; diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs index 7a4122db53..fbc6cf55d5 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs @@ -25,9 +25,11 @@ namespace Microsoft.Net.Server // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. // Assert.Equal(2, requestHeaders.Count); // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); - Assert.Equal("localhost:8080", requestHeaders["Host"].First()); + Assert.Equal("localhost:8080", requestHeaders["Host"]); string[] values; Assert.False(requestHeaders.TryGetValue("Accept", out values)); + Assert.False(requestHeaders.ContainsKey("Accept")); + Assert.Null(requestHeaders["Accept"]); context.Dispose(); string response = await responseTask; @@ -46,13 +48,15 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); var requestHeaders = context.Request.Headers; Assert.Equal(4, requestHeaders.Count); - Assert.Equal("localhost:8080", requestHeaders["Host"].First()); - Assert.Equal("close", requestHeaders["Connection"].First()); - Assert.Equal(1, requestHeaders["Custom-Header"].Length); + Assert.Equal("localhost:8080", requestHeaders["Host"]); + Assert.Equal(new[] { "localhost:8080" }, requestHeaders.GetValues("Host")); + Assert.Equal("close", requestHeaders["Connection"]); + Assert.Equal(new[] { "close" }, requestHeaders.GetValues("Connection")); // Apparently Http.Sys squashes request headers together. - Assert.Equal("custom1, and custom2, custom3", requestHeaders["Custom-Header"].First()); - Assert.Equal(1, requestHeaders["Spacer-Header"].Length); - Assert.Equal("spacervalue, spacervalue", requestHeaders["Spacer-Header"].First()); + Assert.Equal("custom1, and custom2, custom3", requestHeaders["Custom-Header"]); + Assert.Equal(new[] { "custom1", "and custom2", "custom3" }, requestHeaders.GetValues("Custom-Header")); + Assert.Equal("spacervalue, spacervalue", requestHeaders["Spacer-Header"]); + Assert.Equal(new[] { "spacervalue", "spacervalue" }, requestHeaders.GetValues("Spacer-Header")); context.Dispose(); await responseTask; diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs index 25a125372f..30b32dcc07 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs @@ -45,7 +45,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Request.Headers["transfeR-Encoding"] = new[] { " CHunked " }; + context.Request.Headers["transfeR-Encoding"] = " CHunked "; Stream stream = context.Response.Body; stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); stream.Write(new byte[10], 0, 10); @@ -70,7 +70,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Content-lenGth"] = new[] { " 30 " }; + context.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = context.Response.Body; stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); stream.Write(new byte[10], 0, 10); @@ -132,7 +132,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Content-lenGth"] = new[] { " 20 " }; + context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); @@ -148,7 +148,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Content-lenGth"] = new[] { " 10 " }; + context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); @@ -165,7 +165,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Content-lenGth"] = new[] { " 10 " }; + context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[10], 0, 10); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs index 4411ba1d74..d0290f0693 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs @@ -44,7 +44,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders["WWW-Authenticate"] = new string[] { "custom1" }; + responseHeaders["WWW-Authenticate"] = "custom1"; context.Dispose(); // HttpClient would merge the headers no matter what @@ -68,7 +68,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders["WWW-Authenticate"] = new string[] { "custom1, and custom2", "custom3" }; + responseHeaders.SetValues("WWW-Authenticate", "custom1, and custom2", "custom3"); context.Dispose(); // HttpClient would merge the headers no matter what @@ -92,7 +92,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders["Custom-Header1"] = new string[] { "custom1, and custom2", "custom3" }; + responseHeaders.SetValues("Custom-Header1", "custom1, and custom2", "custom3"); context.Dispose(); // HttpClient would merge the headers no matter what @@ -115,7 +115,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders["Connection"] = new string[] { "Close" }; + responseHeaders["Connection"] = "Close"; context.Dispose(); HttpResponseMessage response = await responseTask; @@ -198,7 +198,7 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders["Transfer-Encoding"] = new string[] { "chunked" }; + responseHeaders["Transfer-Encoding"] = "chunked"; await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); @@ -223,8 +223,8 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); - responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); + responseHeaders.SetValues("Custom1", "value1a", "value1b"); + responseHeaders.SetValues("Custom2", "value2a, value2b"); var body = context.Response.Body; body.Flush(); Assert.Throws(() => context.Response.StatusCode = 404); @@ -254,12 +254,12 @@ namespace Microsoft.Net.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); - responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); + responseHeaders.SetValues("Custom1", "value1a", "value1b"); + responseHeaders.SetValues("Custom2", "value2a, value2b"); var body = context.Response.Body; await body.FlushAsync(); Assert.Throws(() => context.Response.StatusCode = 404); - responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored + responseHeaders.SetValues("Custom3", "value3a, value3b", "value3c"); // Ignored context.Dispose(); diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs index ff9fb85c9c..3714c56b98 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs @@ -4,9 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net; using System.Net.Http; -using System.Text; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -91,7 +89,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Transfer-EncodinG"] = new[] { "CHUNKED" }; + context.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -112,7 +110,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Transfer-EncodinG"] = new[] { "CHUNKED" }; + context.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -206,7 +204,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Content-lenGth"] = new[] { FileLength.ToString() }; + context.Response.Headers["Content-lenGth"] = FileLength.ToString(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); HttpResponseMessage response = await responseTask; @@ -227,7 +225,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Content-lenGth"] = new[] { "10" }; + context.Response.Headers["Content-lenGth"] = "10"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); context.Dispose(); @@ -249,7 +247,7 @@ namespace Microsoft.Net.Server Task responseTask = SendRequestAsync(Address); var context = await server.GetContextAsync(); - context.Response.Headers["Content-lenGth"] = new[] { "0" }; + context.Response.Headers["Content-lenGth"] = "0"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); context.Dispose(); From 6fab49b6e0640865bb87730ec18f992df21631fc Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 24 Jul 2014 16:13:03 -0700 Subject: [PATCH 093/597] #52 - Enable parallel tests by using dynamic ports. --- src/Microsoft.Net.Server/UrlPrefix.cs | 34 +++++++-- .../AuthenticationTests.cs | 73 +++++++++++-------- ...t.Server.WebListener.FunctionalTests.kproj | 1 - .../OpaqueUpgradeTests.cs | 30 ++++---- .../Properties/AssemblyInfo.cs | 19 ----- .../RequestBodyTests.cs | 37 ++++++---- .../RequestHeaderTests.cs | 29 ++++---- .../RequestTests.cs | 42 ++++++----- .../ResponseBodyTests.cs | 42 ++++++----- .../ResponseHeaderTests.cs | 59 ++++++++------- .../ResponseSendFileTests.cs | 66 ++++++++++------- .../ResponseTests.cs | 32 ++++---- .../ServerTests.cs | 59 +++++++++------ .../Utilities.cs | 66 +++++++++++++---- .../WebSocketTests.cs | 30 +++++--- .../AuthenticationTests.cs | 32 ++++---- .../HttpsTests.cs | 1 + ...Microsoft.Net.Server.FunctionalTests.kproj | 1 - .../OpaqueUpgradeTests.cs | 24 +++--- .../Properties/AssemblyInfo.cs | 8 -- .../RequestBodyTests.cs | 37 ++++++---- .../RequestHeaderTests.cs | 28 +++---- .../RequestTests.cs | 39 +++++----- .../ResponseBodyTests.cs | 32 ++++---- .../ResponseHeaderTests.cs | 47 +++++++----- .../ResponseSendFileTests.cs | 61 +++++++++------- .../ResponseTests.cs | 32 ++++---- .../ServerTests.cs | 33 +++++---- .../Utilities.cs | 66 +++++++++++++---- .../WebSocketTests.cs | 27 ++++--- 30 files changed, 636 insertions(+), 451 deletions(-) delete mode 100644 test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs delete mode 100644 test/Microsoft.Net.Server.FunctionalTests/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.Net.Server/UrlPrefix.cs b/src/Microsoft.Net.Server/UrlPrefix.cs index f8b8783813..0d1e732bef 100644 --- a/src/Microsoft.Net.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Server/UrlPrefix.cs @@ -47,6 +47,24 @@ namespace Microsoft.Net.Server /// If empty, the default port for the given scheme will be used (80 or 443). /// Should start and end with a '/', though a missing trailing slash will be added. This value must be un-escaped. public static UrlPrefix Create(string scheme, string host, string port, string path) + { + int? portValue = null; + if (!string.IsNullOrWhiteSpace(port)) + { + portValue = int.Parse(port, NumberStyles.None, CultureInfo.InvariantCulture); + } + + return UrlPrefix.Create(scheme, host, portValue, path); + } + + /// + /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa364698(v=vs.85).aspx + /// + /// http or https. Will be normalized to lower case. + /// +, *, IPv4, [IPv6], or a dns name. Http.Sys does not permit punycode (xn--), use Unicode instead. + /// If empty, the default port for the given scheme will be used (80 or 443). + /// Should start and end with a '/', though a missing trailing slash will be added. This value must be un-escaped. + public static UrlPrefix Create(string scheme, string host, int? portValue, string path) { bool isHttps; if (string.Equals(Constants.HttpScheme, scheme, StringComparison.OrdinalIgnoreCase)) @@ -69,15 +87,15 @@ namespace Microsoft.Net.Server throw new ArgumentNullException("host"); } - int portValue; - if (string.IsNullOrWhiteSpace(port)) + string port; + if (!portValue.HasValue) { port = isHttps ? "443" : "80"; portValue = isHttps ? 443 : 80; } else { - portValue = int.Parse(port, NumberStyles.None, CultureInfo.InvariantCulture); + port = portValue.Value.ToString(CultureInfo.InvariantCulture); } // Http.Sys requires the path end with a slash. @@ -90,14 +108,14 @@ namespace Microsoft.Net.Server path += "/"; } - return new UrlPrefix(isHttps, scheme, host, port, portValue, path); + return new UrlPrefix(isHttps, scheme, host, port, portValue.Value, path); } public static UrlPrefix Create(string prefix) { string scheme = null; string host = null; - string port = null; + int? port = null; string path = null; string whole = prefix ?? string.Empty; @@ -123,11 +141,11 @@ namespace Microsoft.Net.Server scheme = whole.Substring(0, delimiterStart1); string portString = whole.Substring(delimiterEnd2, delimiterStart3 - delimiterEnd2); - int ignored; - if (int.TryParse(portString, NumberStyles.Integer, CultureInfo.InvariantCulture, out ignored)) + int portValue; + if (int.TryParse(portString, NumberStyles.Integer, CultureInfo.InvariantCulture, out portValue)) { host = whole.Substring(delimiterEnd1, delimiterStart2 - delimiterEnd1); - port = portString; + port = portValue; } else { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index db7417482d..acb4313ea1 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -29,8 +29,6 @@ namespace Microsoft.AspNet.Server.WebListener { public class AuthenticationTests { - private const string Address = "http://localhost:8080/"; - [Theory] [InlineData(AuthenticationTypes.AllowAnonymous)] [InlineData(AuthenticationTypes.Kerberos)] @@ -41,7 +39,8 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType) { - using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + string address; + using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -49,7 +48,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(0, response.Headers.WwwAuthenticate.Count); } @@ -63,12 +62,13 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Basic)] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType) { - using (Utilities.CreateAuthServer(authType, env => + string address; + using (Utilities.CreateHttpAuthServer(authType, out address, env => { throw new NotImplementedException(); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } @@ -82,7 +82,8 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Basic)] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType) { - using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + string address; + using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -91,7 +92,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } @@ -100,13 +101,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { - using (Utilities.CreateAuthServer( + string address; + using (Utilities.CreateHttpAuthServer( AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM /* | AuthenticationTypes.Digest TODO: Not implemented */ | AuthenticationTypes.Basic | AuthenticationTypes.AllowAnonymous, + out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); @@ -116,7 +119,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal("Kerberos, Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } @@ -131,8 +134,9 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType) { + string address; int requestId = 0; - using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -153,7 +157,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address, useDefaultCredentials: true); + var response = await SendRequestAsync(address, useDefaultCredentials: true); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } @@ -167,7 +171,8 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType) { - using (Utilities.CreateAuthServer(authType, env => + string address; + using (Utilities.CreateHttpAuthServer(authType, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -175,7 +180,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address, useDefaultCredentials: true); + var response = await SendRequestAsync(address, useDefaultCredentials: true); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } @@ -190,7 +195,8 @@ namespace Microsoft.AspNet.Server.WebListener // [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_GetSingleDescriptions(AuthenticationTypes authType) { - using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + string address; + using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); var resultList = context.GetAuthenticationTypes(); @@ -209,7 +215,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(0, response.Headers.WwwAuthenticate.Count); } @@ -218,13 +224,14 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task AuthTypes_GetMultipleDescriptions() { + string address; AuthenticationTypes authType = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic; - using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); var resultList = context.GetAuthenticationTypes(); @@ -232,7 +239,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(0, response.Headers.WwwAuthenticate.Count); } @@ -247,8 +254,9 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationTypes authType) { + string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -258,7 +266,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(0, response.Headers.WwwAuthenticate.Count); } @@ -273,8 +281,9 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationTypes authType) { + string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateAuthServer(authType, env => + using (Utilities.CreateHttpAuthServer(authType, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -284,7 +293,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address, useDefaultCredentials: true); + var response = await SendRequestAsync(address, useDefaultCredentials: true); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } @@ -298,8 +307,9 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationTypes authType) { + string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -308,7 +318,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count); } @@ -323,8 +333,9 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationTypes authType) { + string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -333,7 +344,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count); } @@ -347,8 +358,9 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Basic)] public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationTypes authType) { + string address; var authTypes = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic; - using (Utilities.CreateAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, env => + using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -357,7 +369,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(1, response.Headers.WwwAuthenticate.Count); Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.First().Scheme); @@ -372,10 +384,11 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData(AuthenticationTypes.Basic)] public async Task AuthTypes_ChallengeDisabledAuthType_Error(AuthenticationTypes authType) { + string address; var authTypes = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic; authTypes = authTypes & ~authType; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, env => + using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -384,7 +397,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - var response = await SendRequestAsync(Address); + var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(0, response.Headers.WwwAuthenticate.Count); } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj index afd9e549f3..93e75d54f4 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj @@ -22,7 +22,6 @@ - diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 345092d7ff..cfbcb1827c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -16,7 +16,6 @@ // permissions and limitations under the License. using System; -using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Net.Sockets; @@ -24,8 +23,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.Http; +using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; using Xunit; @@ -33,12 +32,11 @@ namespace Microsoft.AspNet.Server.WebListener { public class OpaqueUpgradeTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task OpaqueUpgrade_SupportKeys_Present() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -53,7 +51,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); Assert.Equal(0, response.Content.Headers.ContentLength); @@ -65,7 +63,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task OpaqueUpgrade_AfterHeadersSent_Throws() { bool? upgradeThrew = null; - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); await httpContext.Response.WriteAsync("Hello World"); @@ -82,7 +81,7 @@ namespace Microsoft.AspNet.Server.WebListener } })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); Assert.True(upgradeThrew.Value); @@ -94,7 +93,8 @@ namespace Microsoft.AspNet.Server.WebListener { ManualResetEvent waitHandle = new ManualResetEvent(false); bool? upgraded = null; - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets @@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Server.WebListener waitHandle.Set(); })) { - using (Stream stream = await SendOpaqueRequestAsync("GET", Address)) + using (Stream stream = await SendOpaqueRequestAsync("GET", address)) { Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); Assert.True(upgraded.HasValue, "Upgraded not set"); @@ -140,7 +140,8 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData("PUT", "Content-Length: 0")] public async Task OpaqueUpgrade_VariousMethodsUpgradeSendAndReceive_Success(string method, string extraHeader) { - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -162,7 +163,7 @@ namespace Microsoft.AspNet.Server.WebListener } })) { - using (Stream stream = await SendOpaqueRequestAsync(method, Address, extraHeader)) + using (Stream stream = await SendOpaqueRequestAsync(method, address, extraHeader)) { byte[] data = new byte[100]; stream.WriteAsync(data, 0, 49).Wait(); @@ -182,7 +183,8 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData("CUSTOMVERB", "Transfer-Encoding: chunked")] public async Task OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) { - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -197,7 +199,7 @@ namespace Microsoft.AspNet.Server.WebListener } })) { - await Assert.ThrowsAsync(async () => await SendOpaqueRequestAsync(method, Address, extraHeader)); + await Assert.ThrowsAsync(async () => await SendOpaqueRequestAsync(method, address, extraHeader)); } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs deleted file mode 100644 index a462d9475f..0000000000 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// These tests can't run in parallel because they all use the same port. -[assembly: Xunit.CollectionBehaviorAttribute(Xunit.CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 62edea48b6..8a92ce2a04 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -31,12 +31,11 @@ namespace Microsoft.AspNet.Server.WebListener { public class RequestBodyTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task RequestBody_ReadSync_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; @@ -46,7 +45,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - string response = await SendRequestAsync(Address, "Hello World"); + string response = await SendRequestAsync(address, "Hello World"); Assert.Equal("Hello World", response); } } @@ -54,7 +53,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task RequestBody_ReadAync_Success() { - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; @@ -63,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener await httpContext.Response.Body.WriteAsync(input, 0, read); })) { - string response = await SendRequestAsync(Address, "Hello World"); + string response = await SendRequestAsync(address, "Hello World"); Assert.Equal("Hello World", response); } } @@ -71,7 +71,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task RequestBody_ReadBeginEnd_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; @@ -81,7 +82,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - string response = await SendRequestAsync(Address, "Hello World"); + string response = await SendRequestAsync(address, "Hello World"); Assert.Equal("Hello World", response); } } @@ -90,7 +91,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task RequestBody_InvalidBuffer_ArgumentException() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; @@ -104,7 +106,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - string response = await SendRequestAsync(Address, "Hello World"); + string response = await SendRequestAsync(address, "Hello World"); Assert.Equal(string.Empty, response); } } @@ -113,7 +115,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestBody_ReadSyncPartialBody_Success() { StaggardContent content = new StaggardContent(); - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[10]; @@ -125,7 +128,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - string response = await SendRequestAsync(Address, content); + string response = await SendRequestAsync(address, content); Assert.Equal(string.Empty, response); } } @@ -134,7 +137,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestBody_ReadAsyncPartialBody_Success() { StaggardContent content = new StaggardContent(); - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[10]; @@ -145,7 +149,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(5, read); })) { - string response = await SendRequestAsync(Address, content); + string response = await SendRequestAsync(address, content); Assert.Equal(string.Empty, response); } } @@ -153,7 +157,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task RequestBody_PostWithImidateBody_Success() { - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[11]; @@ -165,7 +170,7 @@ namespace Microsoft.AspNet.Server.WebListener await httpContext.Response.Body.WriteAsync(input, 0, 10); })) { - string response = await SendSocketRequestAsync(Address); + string response = await SendSocketRequestAsync(address); string[] lines = response.Split('\r', '\n'); Assert.Equal(13, lines.Length); Assert.Equal("HTTP/1.1 200 OK", lines[0]); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index d87dadcc65..14af34cc55 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -28,23 +28,22 @@ namespace Microsoft.AspNet.Server.WebListener { public class RequestHeaderTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task RequestHeaders_ClientSendsDefaultHeaders_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. // Assert.Equal(2, requestHeaders.Count); // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); - Assert.Equal("localhost:8080", requestHeaders.Get("Host")); + Assert.NotNull(requestHeaders.Get("Host")); Assert.Equal(null, requestHeaders.Get("Accept")); return Task.FromResult(0); })) { - string response = await SendRequestAsync(Address); + string response = await SendRequestAsync(address); Assert.Equal(string.Empty, response); } } @@ -52,23 +51,24 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task RequestHeaders_ClientSendsCustomHeaders_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; Assert.Equal(4, requestHeaders.Count); - Assert.Equal("localhost:8080", requestHeaders.Get("Host")); + Assert.NotNull(requestHeaders.Get("Host")); Assert.Equal("close", requestHeaders.Get("Connection")); - Assert.Equal(1, requestHeaders["Custom-Header"].Length); // Apparently Http.Sys squashes request headers together. + Assert.Equal(1, requestHeaders.GetValues("Custom-Header").Count); Assert.Equal("custom1, and custom2, custom3", requestHeaders.Get("Custom-Header")); - Assert.Equal(1, requestHeaders["Spacer-Header"].Length); + Assert.Equal(1, requestHeaders.GetValues("Spacer-Header").Count); Assert.Equal("spacervalue, spacervalue", requestHeaders.Get("Spacer-Header")); return Task.FromResult(0); })) { string[] customValues = new string[] { "custom1, and custom2", "custom3" }; - await SendRequestAsync("localhost", 8080, "Custom-Header", customValues); + await SendRequestAsync(address, "Custom-Header", customValues); } } @@ -80,15 +80,14 @@ namespace Microsoft.AspNet.Server.WebListener } } - private async Task SendRequestAsync(string host, int port, string customHeader, string[] customValues) + private async Task SendRequestAsync(string address, string customHeader, string[] customValues) { + var uri = new Uri(address); StringBuilder builder = new StringBuilder(); builder.AppendLine("GET / HTTP/1.1"); builder.AppendLine("Connection: close"); builder.Append("HOST: "); - builder.Append(host); - builder.Append(':'); - builder.AppendLine(port.ToString()); + builder.AppendLine(uri.Authority); foreach (string value in customValues) { builder.Append(customHeader); @@ -101,7 +100,7 @@ namespace Microsoft.AspNet.Server.WebListener byte[] request = Encoding.ASCII.GetBytes(builder.ToString()); Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); - socket.Connect(host, port); + socket.Connect(uri.Host, uri.Port); socket.Send(request); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 57bb19b423..1cd71e5a03 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -32,12 +32,11 @@ namespace Microsoft.AspNet.Server.WebListener public class RequestTests { - private const string Address = "http://localhost:8080"; - [Fact] public async Task Request_SimpleGet_Success() { - using (Utilities.CreateServer("http", "localhost", "8080", "/basepath", env => + string root; + using (Utilities.CreateHttpServerReturnRoot("/basepath", out root, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -77,21 +76,22 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - string response = await SendRequestAsync(Address + "/basepath/SomePath?SomeQuery"); + string response = await SendRequestAsync(root + "/basepath/SomePath?SomeQuery"); Assert.Equal(string.Empty, response); } } [Theory] - [InlineData("/", "http://localhost:8080/", "", "/")] - [InlineData("/basepath/", "http://localhost:8080/basepath", "/basepath", "")] - [InlineData("/basepath/", "http://localhost:8080/basepath/", "/basepath", "/")] - [InlineData("/basepath/", "http://localhost:8080/basepath/subpath", "/basepath", "/subpath")] - [InlineData("/base path/", "http://localhost:8080/base%20path/sub path", "/base path", "/sub path")] - [InlineData("/base葉path/", "http://localhost:8080/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] - public async Task Request_PathSplitting(string pathBase, string requestUri, string expectedPathBase, string expectedPath) + [InlineData("/", "/", "", "/")] + [InlineData("/basepath/", "/basepath", "/basepath", "")] + [InlineData("/basepath/", "/basepath/", "/basepath", "/")] + [InlineData("/basepath/", "/basepath/subpath", "/basepath", "/subpath")] + [InlineData("/base path/", "/base%20path/sub path", "/base path", "/sub path")] + [InlineData("/base葉path/", "/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] + public async Task Request_PathSplitting(string pathBase, string requestPath, string expectedPathBase, string expectedPath) { - using (Utilities.CreateServer("http", "localhost", "8080", pathBase, env => + string root; + using (Utilities.CreateHttpServerReturnRoot(pathBase, out root, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -104,7 +104,6 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(expectedPath, requestInfo.Path); Assert.Equal(expectedPathBase, requestInfo.PathBase); Assert.Equal(string.Empty, requestInfo.QueryString); - Assert.Equal(8080, connectionInfo.LocalPort); } catch (Exception ex) { @@ -114,7 +113,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - string response = await SendRequestAsync(requestUri); + string response = await SendRequestAsync(root + requestPath); Assert.Equal(string.Empty, response); } } @@ -132,9 +131,10 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData("/2/3", "/2/3", "")] [InlineData("/2/3/", "/2/3", "/")] [InlineData("/2/3/random", "/2/3", "/random")] - public async Task Request_MultiplePrefixes(string requestUri, string expectedPathBase, string expectedPath) + public async Task Request_MultiplePrefixes(string requestPath, string expectedPathBase, string expectedPath) { - using (CreateServer(env => + string root; + using (CreateServer(out root, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var requestInfo = httpContext.GetFeature(); @@ -151,19 +151,23 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - string response = await SendRequestAsync(Address + requestUri); + string response = await SendRequestAsync(root + requestPath); Assert.Equal(string.Empty, response); } } - private IDisposable CreateServer(AppFunc app) + private IDisposable CreateServer(out string root, AppFunc app) { + // TODO: We're just doing this to get a dynamic port. This can be removed later when we add support for hot-adding prefixes. + var server = Utilities.CreateHttpServerReturnRoot("/", out root, app); + server.Dispose(); + var rootUri = new Uri(root); var factory = new ServerFactory(loggerFactory: null); var serverInfo = (ServerInformation)factory.Initialize(configuration: null); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create("http", "localhost", "8080", path)); + serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); } return factory.Start(serverInfo, app); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 3aa245dddb..11acdde941 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -30,19 +30,18 @@ namespace Microsoft.AspNet.Server.WebListener { public class ResponseBodyTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Body.Write(new byte[10], 0, 10); return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; @@ -55,7 +54,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseBody_WriteChunked_Chunked() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Request.Headers["transfeR-Encoding"] = " CHunked "; @@ -65,7 +65,7 @@ namespace Microsoft.AspNet.Server.WebListener return stream.WriteAsync(new byte[10], 0, 10); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; @@ -78,7 +78,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseBody_WriteContentLength_PassedThrough() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 30 "; @@ -88,7 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener return stream.WriteAsync(new byte[10], 0, 10); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable contentLength; @@ -102,14 +103,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseBody_Http10WriteNoHeaders_DefaultsConnectionClose() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { env["owin.ResponseProtocol"] = "HTTP/1.0"; env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); // Http.Sys won't transmit 1.0 IEnumerable ignored; @@ -122,21 +124,23 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseBody_WriteContentLengthNoneWritten_Throws() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 20 "; return Task.FromResult(0); })) { - await Assert.ThrowsAsync(() => SendRequestAsync(Address)); + await Assert.ThrowsAsync(() => SendRequestAsync(address)); } } [Fact] public void ResponseBody_WriteContentLengthNotEnoughWritten_Throws() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 20 "; @@ -144,14 +148,15 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - Assert.Throws(() => SendRequestAsync(Address).Result); + Assert.Throws(() => SendRequestAsync(address).Result); } } [Fact] public void ResponseBody_WriteContentLengthTooMuchWritten_Throws() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 10 "; @@ -160,7 +165,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - Assert.Throws(() => SendRequestAsync(Address).Result); + Assert.Throws(() => SendRequestAsync(address).Result); } } @@ -169,7 +174,8 @@ namespace Microsoft.AspNet.Server.WebListener { ManualResetEvent waitHandle = new ManualResetEvent(false); bool? appThrew = null; - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { try { @@ -188,7 +194,7 @@ namespace Microsoft.AspNet.Server.WebListener })) { // The full response is received. - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable contentLength; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 726455a650..c086ce3cea 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -29,17 +29,16 @@ namespace Microsoft.AspNet.Server.WebListener { public class ResponseHeaderTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task ResponseHeaders_ServerSendsDefaultHeaders_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); response.EnsureSuccessStatusCode(); Assert.Equal(2, response.Headers.Count()); Assert.False(response.Headers.TransferEncodingChunked.HasValue); @@ -53,7 +52,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseHeaders_ServerSendsSingleValueKnownHeaders_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -63,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener })) { // HttpClient would merge the headers no matter what - WebRequest request = WebRequest.Create(Address); + WebRequest request = WebRequest.Create(address); HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync(); Assert.Equal(4, response.Headers.Count); Assert.Null(response.Headers["Transfer-Encoding"]); @@ -77,7 +77,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseHeaders_ServerSendsMultiValueKnownHeaders_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -87,7 +88,7 @@ namespace Microsoft.AspNet.Server.WebListener })) { // HttpClient would merge the headers no matter what - WebRequest request = WebRequest.Create(Address); + WebRequest request = WebRequest.Create(address); HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync(); Assert.Equal(4, response.Headers.Count); Assert.Null(response.Headers["Transfer-Encoding"]); @@ -101,7 +102,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -111,7 +113,7 @@ namespace Microsoft.AspNet.Server.WebListener })) { // HttpClient would merge the headers no matter what - WebRequest request = WebRequest.Create(Address); + WebRequest request = WebRequest.Create(address); HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync(); Assert.Equal(4, response.Headers.Count); Assert.Null(response.Headers["Transfer-Encoding"]); @@ -125,7 +127,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseHeaders_ServerSendsConnectionClose_Closed() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -134,7 +137,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); response.EnsureSuccessStatusCode(); Assert.True(response.Headers.ConnectionClose.Value); Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); @@ -144,13 +147,14 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseHeaders_SendsHttp10_Gets11Close() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { env["owin.ResponseProtocol"] = "HTTP/1.0"; return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); response.EnsureSuccessStatusCode(); Assert.Equal(new Version(1, 1), response.Version); Assert.True(response.Headers.ConnectionClose.Value); @@ -161,13 +165,14 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseHeaders_SendsHttp10WithBody_Gets11Close() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { env["owin.ResponseProtocol"] = "HTTP/1.0"; return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); response.EnsureSuccessStatusCode(); Assert.Equal(new Version(1, 1), response.Version); Assert.False(response.Headers.TransferEncodingChunked.HasValue); @@ -181,14 +186,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseHeaders_HTTP10Request_Gets11Close() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { return Task.FromResult(0); })) { using (HttpClient client = new HttpClient()) { - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Address); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, address); request.Version = new Version(1, 0); HttpResponseMessage response = await client.SendAsync(request); response.EnsureSuccessStatusCode(); @@ -202,7 +208,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseHeaders_HTTP10Request_RemovesChunkedHeader() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -213,7 +220,7 @@ namespace Microsoft.AspNet.Server.WebListener { using (HttpClient client = new HttpClient()) { - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Address); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, address); request.Version = new Version(1, 0); HttpResponseMessage response = await client.SendAsync(request); response.EnsureSuccessStatusCode(); @@ -229,8 +236,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Headers_FlushSendsHeaders_Success() { - using (Utilities.CreateHttpServer( - env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -244,7 +251,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); response.EnsureSuccessStatusCode(); Assert.Equal(5, response.Headers.Count()); // Date, Server, Chunked @@ -259,8 +266,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Headers_FlushAsyncSendsHeaders_Success() { - using (Utilities.CreateHttpServer( - async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.GetFeature(); @@ -273,7 +280,7 @@ namespace Microsoft.AspNet.Server.WebListener responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); response.EnsureSuccessStatusCode(); Assert.Equal(5, response.Headers.Count()); // Date, Server, Chunked diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index eda1f7c2de..c02cd06f21 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -33,7 +33,6 @@ namespace Microsoft.AspNet.Server.WebListener { public class ResponseSendFileTests { - private const string Address = "http://localhost:8080/"; private readonly string AbsoluteFilePath; private readonly string RelativeFilePath; private readonly long FileLength; @@ -48,7 +47,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_SupportKeys_Present() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable ignored; Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); @@ -91,7 +91,8 @@ namespace Microsoft.AspNet.Server.WebListener { ManualResetEvent waitHandle = new ManualResetEvent(false); bool? appThrew = null; - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -112,7 +113,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.True(waitHandle.WaitOne(100)); Assert.True(appThrew.HasValue, "appThrew.HasValue"); @@ -123,14 +124,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable ignored; Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); @@ -142,14 +144,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_RelativeFile_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable ignored; Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); @@ -161,7 +164,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_Chunked_Chunked() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -169,7 +173,7 @@ namespace Microsoft.AspNet.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -181,7 +185,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_MultipleChunks_Chunked() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -190,7 +195,7 @@ namespace Microsoft.AspNet.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -202,14 +207,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_ChunkedHalfOfFile_Chunked() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -221,14 +227,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_ChunkedOffsetOutOfRange_Throws() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(500, (int)response.StatusCode); } } @@ -236,14 +243,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_ChunkedCountOutOfRange_Throws() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(500, (int)response.StatusCode); } } @@ -251,14 +259,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_ChunkedCount0_Chunked() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -270,7 +279,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_ContentLength_PassedThrough() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -278,7 +288,7 @@ namespace Microsoft.AspNet.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -291,7 +301,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_ContentLengthSpecific_PassedThrough() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -299,7 +310,7 @@ namespace Microsoft.AspNet.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -312,7 +323,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task ResponseSendFile_ContentLength0_PassedThrough() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); @@ -320,7 +332,7 @@ namespace Microsoft.AspNet.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index 7e411dba05..6d7d13af0c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -28,19 +28,18 @@ namespace Microsoft.AspNet.Server.WebListener { public class ResponseTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task Response_ServerSendsDefaultResponse_ServerProvidesStatusCodeAndReasonPhrase() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); Assert.Equal(200, httpContext.Response.StatusCode); return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal("OK", response.ReasonPhrase); Assert.Equal(new Version(1, 1), response.Version); @@ -51,7 +50,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Response_ServerSendsSpecificStatus_ServerProvidesReasonPhrase() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 201; @@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(201, (int)response.StatusCode); Assert.Equal("Created", response.ReasonPhrase); Assert.Equal(new Version(1, 1), response.Version); @@ -70,7 +70,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Response_ServerSendsSpecificStatusAndReasonPhrase_PassedThrough() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 201; @@ -79,7 +80,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(201, (int)response.StatusCode); Assert.Equal("CustomReasonPhrase", response.ReasonPhrase); Assert.Equal(new Version(1, 1), response.Version); @@ -90,14 +91,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Response_ServerSendsCustomStatus_NoReasonPhrase() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 901; return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(901, (int)response.StatusCode); Assert.Equal(string.Empty, response.ReasonPhrase); Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); @@ -107,14 +109,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Response_100_Throws() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 100; return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(500, (int)response.StatusCode); } } @@ -122,14 +125,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Response_0_Throws() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 0; return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 23ff1f232a..16c9cfa70a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -34,17 +34,16 @@ namespace Microsoft.AspNet.Server.WebListener { public class ServerTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task Server_200OK_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { return Task.FromResult(0); })) { - string response = await SendRequestAsync(Address); + string response = await SendRequestAsync(address); Assert.Equal(string.Empty, response); } } @@ -52,14 +51,15 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Server_SendHelloWorld_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentLength = 11; return httpContext.Response.WriteAsync("Hello World"); })) { - string response = await SendRequestAsync(Address); + string response = await SendRequestAsync(address); Assert.Equal("Hello World", response); } } @@ -67,7 +67,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Server_EchoHelloWorld_Success() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); string input = new StreamReader(httpContext.Request.Body).ReadToEnd(); @@ -76,7 +77,7 @@ namespace Microsoft.AspNet.Server.WebListener return httpContext.Response.WriteAsync("Hello World"); })) { - string response = await SendRequestAsync(Address, "Hello World"); + string response = await SendRequestAsync(address, "Hello World"); Assert.Equal("Hello World", response); } } @@ -86,7 +87,8 @@ namespace Microsoft.AspNet.Server.WebListener { Task responseTask; ManualResetEvent received = new ManualResetEvent(false); - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { received.Set(); var httpContext = new DefaultHttpContext((IFeatureCollection)env); @@ -94,7 +96,7 @@ namespace Microsoft.AspNet.Server.WebListener return httpContext.Response.WriteAsync("Hello World"); })) { - responseTask = SendRequestAsync(Address); + responseTask = SendRequestAsync(address); Assert.True(received.WaitOne(10000)); } string response = await responseTask; @@ -104,16 +106,17 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public void Server_AppException_ClientReset() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { throw new InvalidOperationException(); })) { - Task requestTask = SendRequestAsync(Address); + Task requestTask = SendRequestAsync(address); Assert.Throws(() => requestTask.Result); // Do it again to make sure the server didn't crash - requestTask = SendRequestAsync(Address); + requestTask = SendRequestAsync(address); Assert.Throws(() => requestTask.Result); } } @@ -125,7 +128,8 @@ namespace Microsoft.AspNet.Server.WebListener int requestCount = 0; TaskCompletionSource tcs = new TaskCompletionSource(); - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { if (Interlocked.Increment(ref requestCount) == requestLimit) { @@ -142,7 +146,7 @@ namespace Microsoft.AspNet.Server.WebListener List requestTasks = new List(); for (int i = 0; i < requestLimit; i++) { - Task requestTask = SendRequestAsync(Address); + Task requestTask = SendRequestAsync(address); requestTasks.Add(requestTask); } @@ -162,7 +166,8 @@ namespace Microsoft.AspNet.Server.WebListener int requestCount = 0; TaskCompletionSource tcs = new TaskCompletionSource(); - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { if (Interlocked.Increment(ref requestCount) == requestLimit) { @@ -177,7 +182,7 @@ namespace Microsoft.AspNet.Server.WebListener List requestTasks = new List(); for (int i = 0; i < requestLimit; i++) { - Task requestTask = SendRequestAsync(Address); + Task requestTask = SendRequestAsync(address); requestTasks.Add(requestTask); } Assert.True(Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(2)), "Timed out"); @@ -192,7 +197,8 @@ namespace Microsoft.AspNet.Server.WebListener ManualResetEvent aborted = new ManualResetEvent(false); ManualResetEvent canceled = new ManualResetEvent(false); - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); CancellationToken ct = httpContext.RequestAborted; @@ -208,7 +214,7 @@ namespace Microsoft.AspNet.Server.WebListener { // Note: System.Net.Sockets does not RST the connection by default, it just FINs. // Http.Sys's disconnect notice requires a RST. - using (Socket socket = await SendHungRequestAsync("GET", Address)) + using (Socket socket = await SendHungRequestAsync("GET", address)) { Assert.True(received.WaitOne(interval), "Receive Timeout"); socket.Close(0); // Force a RST @@ -226,7 +232,8 @@ namespace Microsoft.AspNet.Server.WebListener ManualResetEvent aborted = new ManualResetEvent(false); ManualResetEvent canceled = new ManualResetEvent(false); - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); CancellationToken ct = httpContext.RequestAborted; @@ -240,7 +247,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - using (Socket socket = await SendHungRequestAsync("GET", Address)) + using (Socket socket = await SendHungRequestAsync("GET", address)) { Assert.True(received.WaitOne(interval), "Receive Timeout"); Assert.Throws(() => socket.Receive(new byte[10])); @@ -251,15 +258,19 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Server_SetQueueLimit_Success() { - var factory = new ServerFactory(loggerFactory: null); + // TODO: This is just to get a dynamic port + string address; + using (Utilities.CreateHttpServer(out address, env => Task.FromResult(0))) { } + + var factory = new ServerFactory(loggerFactory: null); var serverInfo = (ServerInformation)factory.Initialize(configuration: null); - serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create("http://localhost:8080")); + serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(address)); serverInfo.Listener.SetRequestQueueLimit(1001); using (factory.Start(serverInfo, env => Task.FromResult(0))) { - string response = await SendRequestAsync(Address); + string response = await SendRequestAsync(address); Assert.Equal(string.Empty, response); } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index 8281848d57..3181a39875 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -25,32 +25,68 @@ namespace Microsoft.AspNet.Server.WebListener internal static class Utilities { - internal static IDisposable CreateHttpServer(AppFunc app) + private const int BasePort = 5001; + private const int MaxPort = 8000; + private static int NextPort = BasePort; + private static object PortLock = new object(); + + internal static IDisposable CreateHttpServer(out string baseAddress, AppFunc app) { - return CreateServer("http", "localhost", "8080", string.Empty, app); + string root; + return CreateDynamicHttpServer(string.Empty, AuthenticationTypes.AllowAnonymous, out root, out baseAddress, app); + } + + internal static IDisposable CreateHttpServerReturnRoot(string path, out string root, AppFunc app) + { + string baseAddress; + return CreateDynamicHttpServer(path, AuthenticationTypes.AllowAnonymous, out root, out baseAddress, app); + } + + internal static IDisposable CreateHttpAuthServer(AuthenticationTypes authType, out string baseAddress, AppFunc app) + { + string root; + return CreateDynamicHttpServer(string.Empty, authType, out root, out baseAddress, app); + } + + internal static IDisposable CreateDynamicHttpServer(string basePath, AuthenticationTypes authType, out string root, out string baseAddress, AppFunc app) + { + var factory = new ServerFactory(loggerFactory: null); + lock (PortLock) + { + while (NextPort < MaxPort) + { + + var port = NextPort++; + var prefix = UrlPrefix.Create("http", "localhost", port, basePath); + root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; + baseAddress = prefix.ToString(); + + var serverInfo = (ServerInformation)factory.Initialize(configuration: null); + serverInfo.Listener.UrlPrefixes.Add(prefix); + serverInfo.Listener.AuthenticationManager.AuthenticationTypes = authType; + try + { + return factory.Start(serverInfo, app); + } + catch (WebListenerException) + { + } + } + NextPort = BasePort; + } + throw new Exception("Failed to locate a free port."); } internal static IDisposable CreateHttpsServer(AppFunc app) { - return CreateServer("https", "localhost", "9090", string.Empty, app); + return CreateServer("https", "localhost", 9090, string.Empty, app); } - internal static IDisposable CreateAuthServer(AuthenticationTypes authType, AppFunc app) - { - return CreateServer("http", "localhost", "8080", string.Empty, authType, app); - } - - internal static IDisposable CreateServer(string scheme, string host, string port, string path, AppFunc app) - { - return CreateServer(scheme, host, port, path, AuthenticationTypes.AllowAnonymous, app); - } - - internal static IDisposable CreateServer(string scheme, string host, string port, string path, AuthenticationTypes authType, AppFunc app) + internal static IDisposable CreateServer(string scheme, string host, int port, string path, AppFunc app) { var factory = new ServerFactory(loggerFactory: null); var serverInfo = (ServerInformation)factory.Initialize(configuration: null); serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); - serverInfo.Listener.AuthenticationManager.AuthenticationTypes = authType; return factory.Start(serverInfo, app); } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index 3b830843d6..c35719bd76 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -30,13 +30,11 @@ namespace Microsoft.AspNet.Server.WebListener { public class WebSocketTests { - private const string Address = "http://localhost:8080/"; - private const string WsAddress = "ws://localhost:8080/"; - [Fact] public async Task WebSocketTests_SupportKeys_Present() { - using (Utilities.CreateHttpServer(env => + string address; + using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); try @@ -51,7 +49,7 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); Assert.Equal(0, response.Content.Headers.ContentLength); @@ -63,7 +61,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task WebSocketTests_AfterHeadersSent_Throws() { bool? upgradeThrew = null; - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); await httpContext.Response.WriteAsync("Hello World"); @@ -80,7 +79,7 @@ namespace Microsoft.AspNet.Server.WebListener } })) { - HttpResponseMessage response = await SendRequestAsync(Address); + HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); Assert.True(upgradeThrew.Value); @@ -92,7 +91,8 @@ namespace Microsoft.AspNet.Server.WebListener { ManualResetEvent waitHandle = new ManualResetEvent(false); bool? upgraded = null; - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var webSocketFeature = httpContext.GetFeature(); @@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Server.WebListener waitHandle.Set(); })) { - using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(WsAddress)) + using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(ConvertToWebSocketAddress(address))) { Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); Assert.True(upgraded.HasValue, "Upgraded not set"); @@ -116,7 +116,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task WebSocketAccept_SendAndReceive_Success() { byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; - using (Utilities.CreateHttpServer(async env => + string address; + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var webSocketFeature = httpContext.GetFeature(); @@ -132,7 +133,7 @@ namespace Microsoft.AspNet.Server.WebListener })) { - using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(WsAddress)) + using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(ConvertToWebSocketAddress(address))) { await clientWebSocket.SendAsync(new ArraySegment(clientBuffer, 0, 3), WebSocketMessageType.Binary, true, CancellationToken.None); @@ -143,6 +144,13 @@ namespace Microsoft.AspNet.Server.WebListener } } + private string ConvertToWebSocketAddress(string address) + { + var builder = new UriBuilder(address); + builder.Scheme = "ws"; + return builder.ToString(); + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) diff --git a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs index 503b515b7e..6c7474f234 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs @@ -10,8 +10,6 @@ namespace Microsoft.Net.Server { public class AuthenticationTests { - private const string Address = "http://localhost:8080/"; - [Theory] [InlineData(AuthenticationTypes.AllowAnonymous)] [InlineData(AuthenticationTypes.Kerberos)] @@ -22,9 +20,10 @@ namespace Microsoft.Net.Server [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType) { - using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) + string address; + using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); Assert.NotNull(context.User); @@ -53,9 +52,10 @@ namespace Microsoft.Net.Server [InlineData(AuthenticationTypes.Basic)] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType) { - using (var server = Utilities.CreateAuthServer(authType)) + string address; + using (var server = Utilities.CreateHttpAuthServer(authType, out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var contextTask = server.GetContextAsync(); // Fails when the server shuts down, the challenge happens internally. @@ -73,9 +73,10 @@ namespace Microsoft.Net.Server [InlineData(AuthenticationTypes.Basic)] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType) { - using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) + string address; + using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); Assert.NotNull(context.User); @@ -93,15 +94,16 @@ namespace Microsoft.Net.Server [Fact] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { + string address; AuthenticationTypes authType = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM /* | AuthenticationTypes.Digest TODO: Not implemented */ | AuthenticationTypes.Basic; - using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) + using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); Assert.NotNull(context.User); @@ -125,9 +127,10 @@ namespace Microsoft.Net.Server [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType) { - using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous)) + string address; + using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address)) { - Task responseTask = SendRequestAsync(Address, useDefaultCredentials: true); + Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); var context = await server.GetContextAsync(); Assert.NotNull(context.User); @@ -156,9 +159,10 @@ namespace Microsoft.Net.Server [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType) { - using (var server = Utilities.CreateAuthServer(authType)) + string address; + using (var server = Utilities.CreateHttpAuthServer(authType, out address)) { - Task responseTask = SendRequestAsync(Address, useDefaultCredentials: true); + Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); var context = await server.GetContextAsync(); Assert.NotNull(context.User); diff --git a/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs index e4c13293eb..cf7aa0296a 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs @@ -11,6 +11,7 @@ namespace Microsoft.Net.Server { public class HttpsTests { + // Note these tests can't use dynamic ports or run concurrently because the ssl cert must be pre-registered with a specific port. private const string Address = "https://localhost:9090/"; [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] diff --git a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj index 228bd0ad9a..a579d02c1f 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj +++ b/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj @@ -22,7 +22,6 @@ - diff --git a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs index cbf99ec975..48bcc03ba2 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -12,21 +12,20 @@ namespace Microsoft.Net.Server { public class OpaqueUpgradeTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task OpaqueUpgrade_AfterHeadersSent_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task clientTask = SendRequestAsync(Address); + Task clientTask = SendRequestAsync(address); var context = await server.GetContextAsync(); byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.Body.Write(body, 0, body.Length); context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket - Assert.ThrowsAsync(async () => await context.UpgradeAsync()); + await Assert.ThrowsAsync(async () => await context.UpgradeAsync()); context.Dispose(); HttpResponseMessage response = await clientTask; Assert.Equal(200, (int)response.StatusCode); @@ -38,9 +37,10 @@ namespace Microsoft.Net.Server [Fact] public async Task OpaqueUpgrade_GetUpgrade_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task clientTask = SendOpaqueRequestAsync("GET", Address); + Task clientTask = SendOpaqueRequestAsync("GET", address); var context = await server.GetContextAsync(); Assert.True(context.IsUpgradableRequest); @@ -80,9 +80,10 @@ namespace Microsoft.Net.Server [InlineData("PUT", "Content-Length: 0")] public async Task OpaqueUpgrade_VariousMethodsUpgradeSendAndReceive_Success(string method, string extraHeader) { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task clientTask = SendOpaqueRequestAsync(method, Address, extraHeader); + Task clientTask = SendOpaqueRequestAsync(method, address, extraHeader); var context = await server.GetContextAsync(); Assert.True(context.IsUpgradableRequest); @@ -119,9 +120,10 @@ namespace Microsoft.Net.Server [InlineData("CUSTOMVERB", "Transfer-Encoding: chunked")] public async Task OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - var clientTask = SendOpaqueRequestAsync(method, Address, extraHeader); + var clientTask = SendOpaqueRequestAsync(method, address, extraHeader); var context = await server.GetContextAsync(); Assert.False(context.IsUpgradableRequest); context.Dispose(); diff --git a/test/Microsoft.Net.Server.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.Net.Server.FunctionalTests/Properties/AssemblyInfo.cs deleted file mode 100644 index 1bc3b800fb..0000000000 --- a/test/Microsoft.Net.Server.FunctionalTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -// These tests can't run in parallel because they all use the same port. -[assembly: Xunit.CollectionBehaviorAttribute(Xunit.CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs index 89f6d14d32..89e24a90c1 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs @@ -14,14 +14,13 @@ namespace Microsoft.Net.Server { public class RequestBodyTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task RequestBody_ReadSync_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address, "Hello World"); + Task responseTask = SendRequestAsync(address, "Hello World"); var context = await server.GetContextAsync(); byte[] input = new byte[100]; @@ -37,9 +36,10 @@ namespace Microsoft.Net.Server [Fact] public async Task RequestBody_ReadAync_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address, "Hello World"); + Task responseTask = SendRequestAsync(address, "Hello World"); var context = await server.GetContextAsync(); byte[] input = new byte[100]; @@ -55,9 +55,10 @@ namespace Microsoft.Net.Server [Fact] public async Task RequestBody_ReadBeginEnd_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address, "Hello World"); + Task responseTask = SendRequestAsync(address, "Hello World"); var context = await server.GetContextAsync(); byte[] input = new byte[100]; @@ -74,9 +75,10 @@ namespace Microsoft.Net.Server [Fact] public async Task RequestBody_InvalidBuffer_ArgumentException() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address, "Hello World"); + Task responseTask = SendRequestAsync(address, "Hello World"); var context = await server.GetContextAsync(); byte[] input = new byte[100]; @@ -98,9 +100,10 @@ namespace Microsoft.Net.Server public async Task RequestBody_ReadSyncPartialBody_Success() { StaggardContent content = new StaggardContent(); - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address, content); + Task responseTask = SendRequestAsync(address, content); var context = await server.GetContextAsync(); byte[] input = new byte[10]; @@ -120,9 +123,10 @@ namespace Microsoft.Net.Server public async Task RequestBody_ReadAsyncPartialBody_Success() { StaggardContent content = new StaggardContent(); - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address, content); + Task responseTask = SendRequestAsync(address, content); var context = await server.GetContextAsync(); byte[] input = new byte[10]; @@ -141,9 +145,10 @@ namespace Microsoft.Net.Server [Fact] public async Task RequestBody_PostWithImidateBody_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendSocketRequestAsync(Address); + Task responseTask = SendSocketRequestAsync(address); var context = await server.GetContextAsync(); byte[] input = new byte[11]; diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs index fbc6cf55d5..3fb03df524 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +using System; using System.Linq; using System.Net.Http; using System.Net.Sockets; @@ -11,21 +12,20 @@ namespace Microsoft.Net.Server { public class RequestHeaderTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task RequestHeaders_ClientSendsDefaultHeaders_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); var requestHeaders = context.Request.Headers; // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. // Assert.Equal(2, requestHeaders.Count); // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); - Assert.Equal("localhost:8080", requestHeaders["Host"]); + Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); string[] values; Assert.False(requestHeaders.TryGetValue("Accept", out values)); Assert.False(requestHeaders.ContainsKey("Accept")); @@ -40,16 +40,17 @@ namespace Microsoft.Net.Server [Fact] public async Task RequestHeaders_ClientSendsCustomHeaders_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { string[] customValues = new string[] { "custom1, and custom2", "custom3" }; - Task responseTask = SendRequestAsync("localhost", 8080, "Custom-Header", customValues); + Task responseTask = SendRequestAsync(address, "Custom-Header", customValues); var context = await server.GetContextAsync(); var requestHeaders = context.Request.Headers; Assert.Equal(4, requestHeaders.Count); - Assert.Equal("localhost:8080", requestHeaders["Host"]); - Assert.Equal(new[] { "localhost:8080" }, requestHeaders.GetValues("Host")); + Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); + Assert.Equal(new[] { new Uri(address).Authority }, requestHeaders.GetValues("Host")); Assert.Equal("close", requestHeaders["Connection"]); Assert.Equal(new[] { "close" }, requestHeaders.GetValues("Connection")); // Apparently Http.Sys squashes request headers together. @@ -71,15 +72,14 @@ namespace Microsoft.Net.Server } } - private async Task SendRequestAsync(string host, int port, string customHeader, string[] customValues) + private async Task SendRequestAsync(string address, string customHeader, string[] customValues) { + var uri = new Uri(address); StringBuilder builder = new StringBuilder(); builder.AppendLine("GET / HTTP/1.1"); builder.AppendLine("Connection: close"); builder.Append("HOST: "); - builder.Append(host); - builder.Append(':'); - builder.AppendLine(port.ToString()); + builder.AppendLine(uri.Authority); foreach (string value in customValues) { builder.Append(customHeader); @@ -92,7 +92,7 @@ namespace Microsoft.Net.Server byte[] request = Encoding.ASCII.GetBytes(builder.ToString()); Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); - socket.Connect(host, port); + socket.Connect(uri.Host, uri.Port); socket.Send(request); diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs index 54ef27e237..cf8205c18e 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs @@ -11,14 +11,13 @@ namespace Microsoft.Net.Server { public class RequestTests { - private const string Address = "http://localhost:8080"; - [Fact] public async Task Request_SimpleGet_Success() { - using (var server = Utilities.CreateServer("http", "localhost", "8080", "/basepath")) + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/basepath", out root)) { - Task responseTask = SendRequestAsync(Address + "/basepath/SomePath?SomeQuery"); + Task responseTask = SendRequestAsync(root + "/basepath/SomePath?SomeQuery"); var context = await server.GetContextAsync(); @@ -51,17 +50,18 @@ namespace Microsoft.Net.Server } [Theory] - [InlineData("/", "http://localhost:8080/", "", "/")] - [InlineData("/basepath/", "http://localhost:8080/basepath", "/basepath", "")] - [InlineData("/basepath/", "http://localhost:8080/basepath/", "/basepath", "/")] - [InlineData("/basepath/", "http://localhost:8080/basepath/subpath", "/basepath", "/subpath")] - [InlineData("/base path/", "http://localhost:8080/base%20path/sub path", "/base path", "/sub path")] - [InlineData("/base葉path/", "http://localhost:8080/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] - public async Task Request_PathSplitting(string pathBase, string requestUri, string expectedPathBase, string expectedPath) + [InlineData("/", "/", "", "/")] + [InlineData("/basepath/", "/basepath", "/basepath", "")] + [InlineData("/basepath/", "/basepath/", "/basepath", "/")] + [InlineData("/basepath/", "/basepath/subpath", "/basepath", "/subpath")] + [InlineData("/base path/", "/base%20path/sub path", "/base path", "/sub path")] + [InlineData("/base葉path/", "/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] + public async Task Request_PathSplitting(string pathBase, string requestPath, string expectedPathBase, string expectedPath) { - using (var server = Utilities.CreateServer("http", "localhost", "8080", pathBase)) + string root; + using (var server = Utilities.CreateHttpServerReturnRoot(pathBase, out root)) { - Task responseTask = SendRequestAsync(requestUri); + Task responseTask = SendRequestAsync(root + requestPath); var context = await server.GetContextAsync(); @@ -73,7 +73,6 @@ namespace Microsoft.Net.Server Assert.Equal(expectedPath, request.Path); Assert.Equal(expectedPathBase, request.PathBase); Assert.Equal(string.Empty, request.QueryString); - Assert.Equal(8080, request.LocalPort); context.Dispose(); string response = await responseTask; @@ -96,15 +95,21 @@ namespace Microsoft.Net.Server [InlineData("/2/3/random", "/2/3", "/random")] public async Task Request_MultiplePrefixes(string requestUri, string expectedPathBase, string expectedPath) { - using (var server = new WebListener()) + // TODO: We're just doing this to get a dynamic port. This can be removed later when we add support for hot-adding prefixes. + string root; + var server = Utilities.CreateHttpServerReturnRoot("/", out root); + server.Dispose(); + server = new WebListener(); + using (server) { + var uriBuilder = new UriBuilder(root); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - server.UrlPrefixes.Add(UrlPrefix.Create("http", "localhost", "8080", path)); + server.UrlPrefixes.Add(UrlPrefix.Create(uriBuilder.Scheme, uriBuilder.Host, uriBuilder.Port, path)); } server.Start(); - Task responseTask = SendRequestAsync(Address + requestUri); + Task responseTask = SendRequestAsync(root + requestUri); var context = await server.GetContextAsync(); var request = context.Request; diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs index 30b32dcc07..299f719f5c 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs @@ -13,14 +13,13 @@ namespace Microsoft.Net.Server { public class ResponseBodyTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Body.Write(new byte[10], 0, 10); @@ -40,9 +39,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseBody_WriteChunked_Chunked() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Request.Headers["transfeR-Encoding"] = " CHunked "; @@ -65,9 +65,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseBody_WriteContentLength_PassedThrough() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 30 "; @@ -127,9 +128,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; @@ -143,9 +145,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; @@ -160,9 +163,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseBody_WriteContentLengthExtraWritten_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs index d0290f0693..ab12512b17 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs @@ -11,14 +11,13 @@ namespace Microsoft.Net.Server { public class ResponseHeaderTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task ResponseHeaders_ServerSendsDefaultHeaders_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Dispose(); @@ -37,9 +36,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseHeaders_ServerSendsSingleValueKnownHeaders_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - WebRequest request = WebRequest.Create(Address); + WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); var context = await server.GetContextAsync(); @@ -61,9 +61,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseHeaders_ServerSendsMultiValueKnownHeaders_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - WebRequest request = WebRequest.Create(Address); + WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); var context = await server.GetContextAsync(); @@ -85,9 +86,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - WebRequest request = WebRequest.Create(Address); + WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); var context = await server.GetContextAsync(); @@ -109,9 +111,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseHeaders_ServerSendsConnectionClose_Closed() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; @@ -165,11 +168,12 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseHeaders_HTTP10Request_Gets11Close() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { using (HttpClient client = new HttpClient()) { - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Address); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, address); request.Version = new Version(1, 0); Task responseTask = client.SendAsync(request); @@ -188,11 +192,12 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseHeaders_HTTP10Request_RemovesChunkedHeader() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { using (HttpClient client = new HttpClient()) { - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Address); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, address); request.Version = new Version(1, 0); Task responseTask = client.SendAsync(request); @@ -216,9 +221,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Headers_FlushSendsHeaders_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; @@ -247,9 +253,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Headers_FlushAsyncSendsHeaders_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs index 3714c56b98..5139d9ad40 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs @@ -13,7 +13,6 @@ namespace Microsoft.Net.Server { public class ResponseSendFileTests { - private const string Address = "http://localhost:8080/"; private readonly string AbsoluteFilePath; private readonly string RelativeFilePath; private readonly long FileLength; @@ -28,9 +27,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_MissingFile_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); await Assert.ThrowsAsync(() => @@ -44,9 +44,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); @@ -64,9 +65,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_RelativeFile_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); await context.Response.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); @@ -84,9 +86,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_Chunked_Chunked() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; @@ -105,9 +108,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_MultipleChunks_Chunked() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; @@ -127,9 +131,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_ChunkedHalfOfFile_Chunked() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); @@ -147,9 +152,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_ChunkedOffsetOutOfRange_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); await Assert.ThrowsAsync( @@ -163,9 +169,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_ChunkedCountOutOfRange_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); await Assert.ThrowsAsync( @@ -179,9 +186,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_ChunkedCount0_Chunked() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); @@ -199,9 +207,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_ContentLength_PassedThrough() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = FileLength.ToString(); @@ -220,9 +229,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_ContentLengthSpecific_PassedThrough() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = "10"; @@ -242,9 +252,10 @@ namespace Microsoft.Net.Server [Fact] public async Task ResponseSendFile_ContentLength0_PassedThrough() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = "0"; diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs index 6aaceeff89..f5d5c2146c 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs @@ -10,14 +10,13 @@ namespace Microsoft.Net.Server { public class ResponseTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task Response_ServerSendsDefaultResponse_ServerProvidesStatusCodeAndReasonPhrase() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); Assert.Equal(200, context.Response.StatusCode); @@ -34,9 +33,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Response_ServerSendsSpecificStatus_ServerProvidesReasonPhrase() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.StatusCode = 201; @@ -54,9 +54,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Response_ServerSendsSpecificStatusAndReasonPhrase_PassedThrough() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.StatusCode = 201; @@ -75,9 +76,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Response_ServerSendsCustomStatus_NoReasonPhrase() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.StatusCode = 901; @@ -93,9 +95,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Response_100_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); Assert.Throws(() => { context.Response.StatusCode = 100; }); @@ -108,9 +111,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Response_0_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); Assert.Throws(() => { context.Response.StatusCode = 0; }); diff --git a/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs index 5778917050..af97555358 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; @@ -15,14 +14,13 @@ namespace Microsoft.Net.Server { public class ServerTests { - private const string Address = "http://localhost:8080/"; - [Fact] public async Task Server_200OK_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Dispose(); @@ -35,9 +33,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Server_SendHelloWorld_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Response.ContentLength = 11; @@ -54,9 +53,10 @@ namespace Microsoft.Net.Server [Fact] public async Task Server_EchoHelloWorld_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(Address, "Hello World"); + Task responseTask = SendRequestAsync(address, "Hello World"); var context = await server.GetContextAsync(); string input = new StreamReader(context.Request.Body).ReadToEnd(); @@ -78,11 +78,12 @@ namespace Microsoft.Net.Server TimeSpan interval = TimeSpan.FromSeconds(1); ManualResetEvent canceled = new ManualResetEvent(false); - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { // Note: System.Net.Sockets does not RST the connection by default, it just FINs. // Http.Sys's disconnect notice requires a RST. - Task responseTask = SendHungRequestAsync("GET", Address); + Task responseTask = SendHungRequestAsync("GET", address); var context = await server.GetContextAsync(); CancellationToken ct = context.DisconnectToken; @@ -107,11 +108,12 @@ namespace Microsoft.Net.Server TimeSpan interval = TimeSpan.FromSeconds(1); ManualResetEvent canceled = new ManualResetEvent(false); - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { // Note: System.Net.Sockets does not RST the connection by default, it just FINs. // Http.Sys's disconnect notice requires a RST. - Task responseTask = SendHungRequestAsync("GET", Address); + Task responseTask = SendHungRequestAsync("GET", address); var context = await server.GetContextAsync(); CancellationToken ct = context.DisconnectToken; @@ -132,10 +134,11 @@ namespace Microsoft.Net.Server [Fact] public async Task Server_SetQueueLimit_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { server.SetRequestQueueLimit(1001); - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Dispose(); diff --git a/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs index e911f5baa2..18c3d31987 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs @@ -6,31 +6,67 @@ namespace Microsoft.Net.Server { internal static class Utilities { - internal static WebListener CreateHttpServer() + private const int BasePort = 5001; + private const int MaxPort = 8000; + private static int NextPort = BasePort; + private static object PortLock = new object(); + + internal static WebListener CreateHttpAuthServer(AuthenticationTypes authType, out string baseAddress) { - return CreateServer("http", "localhost", "8080", string.Empty); + var listener = CreateHttpServer(out baseAddress); + listener.AuthenticationManager.AuthenticationTypes = authType; + return listener; } + internal static WebListener CreateHttpServer(out string baseAddress) + { + string root; + return CreateDynamicHttpServer(string.Empty, out root, out baseAddress); + } + + internal static WebListener CreateHttpServerReturnRoot(string path, out string root) + { + string baseAddress; + return CreateDynamicHttpServer(path, out root, out baseAddress); + } + + internal static WebListener CreateDynamicHttpServer(string basePath, out string root, out string baseAddress) + { + lock (PortLock) + { + while (NextPort < MaxPort) + { + var port = NextPort++; + var prefix = UrlPrefix.Create("http", "localhost", port, basePath); + root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; + baseAddress = prefix.ToString(); + var listener = new WebListener(); + listener.UrlPrefixes.Add(prefix); + try + { + listener.Start(); + return listener; + } + catch (WebListenerException) + { + listener.Dispose(); + } + } + NextPort = BasePort; + } + throw new Exception("Failed to locate a free port."); + } + + internal static WebListener CreateHttpsServer() { - return CreateServer("https", "localhost", "9090", string.Empty); + return CreateServer("https", "localhost", 9090, string.Empty); } - internal static WebListener CreateAuthServer(AuthenticationTypes authType) - { - return CreateServer("http", "localhost", "8080", string.Empty, authType); - } - - internal static WebListener CreateServer(string scheme, string host, string port, string path) - { - return CreateServer(scheme, host, port, path, AuthenticationTypes.AllowAnonymous); - } - - internal static WebListener CreateServer(string scheme, string host, string port, string path, AuthenticationTypes authType) + internal static WebListener CreateServer(string scheme, string host, int port, string path) { WebListener listener = new WebListener(); listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); - listener.AuthenticationManager.AuthenticationTypes = authType; listener.Start(); return listener; } diff --git a/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs index 946aabec14..e54c94740f 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs @@ -12,21 +12,19 @@ namespace Microsoft.Net.Server { public class WebSocketTests { - private const string Address = "http://localhost:8080/"; - private const string WsAddress = "ws://localhost:8080/"; - [Fact] public async Task WebSocketAccept_AfterHeadersSent_Throws() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task clientTask = SendRequestAsync(Address); + Task clientTask = SendRequestAsync(address); var context = await server.GetContextAsync(); byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.Body.Write(body, 0, body.Length); - Assert.ThrowsAsync(async () => await context.AcceptWebSocketAsync()); + await Assert.ThrowsAsync(async () => await context.AcceptWebSocketAsync()); context.Dispose(); HttpResponseMessage response = await clientTask; Assert.Equal(200, (int)response.StatusCode); @@ -38,9 +36,10 @@ namespace Microsoft.Net.Server [Fact] public async Task WebSocketAccept_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task clientTask = SendWebSocketRequestAsync(WsAddress); + Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); var context = await server.GetContextAsync(); Assert.True(context.IsUpgradableRequest); @@ -54,9 +53,10 @@ namespace Microsoft.Net.Server [Fact] public async Task WebSocketAccept_SendAndReceive_Success() { - using (var server = Utilities.CreateHttpServer()) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - Task clientTask = SendWebSocketRequestAsync(WsAddress); + Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); var context = await server.GetContextAsync(); Assert.True(context.IsWebSocketRequest); @@ -81,6 +81,13 @@ namespace Microsoft.Net.Server } } + private string ConvertToWebSocketAddress(string address) + { + var builder = new UriBuilder(address); + builder.Scheme = "ws"; + return builder.ToString(); + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) From f2a99aa352cb9e4f4aa722ed89b1c5959b0be1ac Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 5 Aug 2014 15:50:58 -0700 Subject: [PATCH 094/597] Updating release Nuget.config --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index f41e9c631d..1ce6b9e257 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@ - + - + From 5aa8f3b45944391365670f51b07468e22a8f942c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 6 Aug 2014 12:30:52 -0700 Subject: [PATCH 095/597] Updating dev Nuget.config --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index 1ce6b9e257..f41e9c631d 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@ - + - + From 1416cc4d69381922a0ab8bc7cd52acf6921aec6a Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 6 Aug 2014 15:49:53 -0700 Subject: [PATCH 096/597] #46 - Rename Microsoft.Net.Server to Microsoft.Net.Http.Server. --- WebListener.sln | 11 ++++++++--- samples/HelloWorld/Program.cs | 2 +- samples/HelloWorld/project.json | 2 +- samples/SelfHostServer/Startup.cs | 2 +- samples/SelfHostServer/project.json | 2 +- .../AuthenticationHandler.cs | 2 +- .../FeatureContext.cs | 2 +- .../MessagePump.cs | 8 ++++---- .../ServerFactory.cs | 6 +++--- .../ServerInformation.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- .../AsyncAcceptContext.cs | 2 +- .../AuthenticationManager.cs | 2 +- .../AuthenticationTypes.cs | 2 +- .../Constants.cs | 2 +- .../CustomDictionary.xml | 0 .../GlobalSuppressions.cs | 0 .../Helpers.cs | 2 +- .../LogHelper.cs | 2 +- .../Microsoft.Net.Http.Server.kproj} | 0 .../NativeInterop/AddressFamily.cs | 2 +- .../NativeInterop/ComNetOS.cs | 2 +- .../NativeInterop/ContextAttribute.cs | 2 +- .../NativeInterop/HttpRequestQueueV2Handle.cs | 2 +- .../NativeInterop/HttpServerSessionHandle.cs | 2 +- .../NativeInterop/HttpSysRequestHeader.cs | 2 +- .../NativeInterop/HttpSysResponseHeader.cs | 2 +- .../NativeInterop/HttpSysSettings.cs | 2 +- .../NativeInterop/IntPtrHelper.cs | 2 +- .../NativeInterop/NclUtilities.cs | 2 +- .../NativeInterop/SSPIHandle.cs | 2 +- .../NativeInterop/SafeLoadLibrary.cs | 2 +- .../NativeInterop/SafeLocalFree.cs | 2 +- .../NativeInterop/SafeLocalFreeChannelBinding.cs | 2 +- .../NativeInterop/SafeLocalMemHandle.cs | 2 +- .../NativeInterop/SafeNativeOverlapped.cs | 2 +- .../NativeInterop/SchProtocols.cs | 2 +- .../NativeInterop/SecurityStatus.cs | 2 +- .../NativeInterop/SocketAddress.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 4 ++-- .../RequestProcessing/BoundaryType.cs | 2 +- .../RequestProcessing/ClientCertLoader.cs | 2 +- .../RequestProcessing/HeaderCollection.cs | 2 +- .../RequestProcessing/HeaderEncoding.cs | 2 +- .../RequestProcessing/HeaderParser.cs | 2 +- .../RequestProcessing/HttpKnownHeaderNames.cs | 2 +- .../RequestProcessing/HttpReasonPhrase.cs | 2 +- .../RequestProcessing/HttpStatusCode.cs | 2 +- .../RequestProcessing/NativeRequestContext.cs | 2 +- .../RequestProcessing/OpaqueStream.cs | 2 +- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestContext.cs | 2 +- .../RequestProcessing/RequestHeaders.Generated.cs | 2 +- .../RequestProcessing/RequestHeaders.Generated.tt | 2 +- .../RequestProcessing/RequestHeaders.cs | 2 +- .../RequestProcessing/RequestStream.cs | 2 +- .../RequestProcessing/RequestUriBuilder.cs | 2 +- .../RequestProcessing/Response.cs | 2 +- .../RequestProcessing/ResponseStream.cs | 2 +- .../RequestProcessing/ResponseStreamAsyncResult.cs | 2 +- .../RequestProcessing/SslStatus.cs | 2 +- .../Resources.Designer.cs | 4 ++-- .../Resources.resx | 0 .../TimeoutManager.cs | 2 +- .../UrlPrefix.cs | 2 +- .../ValidationHelper.cs | 2 +- .../WebListener.cs | 2 +- .../WebListenerException.cs | 2 +- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 0 .../SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs | 0 .../fx/System/Diagnostics/TraceEventType.cs | 0 .../fx/System/ExternDll.cs | 0 .../Runtime/InteropServices/ExternalException.cs | 0 .../fx/System/SafeNativeMethods.cs | 0 .../project.json | 0 .../AuthenticationTests.cs | 2 +- .../RequestTests.cs | 2 +- .../ServerTests.cs | 2 +- .../Utilities.cs | 2 +- .../project.json | 2 +- .../AuthenticationTests.cs | 2 +- .../HttpsTests.cs | 2 +- .../Microsoft.Net.Http.Server.FunctionalTests.kproj} | 0 .../OpaqueUpgradeTests.cs | 2 +- .../RequestBodyTests.cs | 2 +- .../RequestHeaderTests.cs | 2 +- .../RequestTests.cs | 2 +- .../ResponseBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 2 +- .../ResponseSendFileTests.cs | 2 +- .../ResponseTests.cs | 2 +- .../ServerTests.cs | 2 +- .../Utilities.cs | 2 +- .../WebSocketTests.cs | 2 +- .../project.json | 2 +- 95 files changed, 97 insertions(+), 92 deletions(-) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/AsyncAcceptContext.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/AuthenticationManager.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/AuthenticationTypes.cs (96%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/Constants.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/CustomDictionary.xml (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/GlobalSuppressions.cs (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/Helpers.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/LogHelper.cs (98%) rename src/{Microsoft.Net.Server/Microsoft.Net.Server.kproj => Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj} (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/AddressFamily.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/ComNetOS.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/ContextAttribute.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/HttpRequestQueueV2Handle.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/HttpServerSessionHandle.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/HttpSysRequestHeader.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/HttpSysResponseHeader.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/HttpSysSettings.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/IntPtrHelper.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/NclUtilities.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SSPIHandle.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SafeLoadLibrary.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SafeLocalFree.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SafeLocalFreeChannelBinding.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SafeLocalMemHandle.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SafeNativeOverlapped.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SchProtocols.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SecurityStatus.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/SocketAddress.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/NativeInterop/UnsafeNativeMethods.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/BoundaryType.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/ClientCertLoader.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/HeaderCollection.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/HeaderEncoding.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/HeaderParser.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/HttpKnownHeaderNames.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/HttpReasonPhrase.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/HttpStatusCode.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/NativeRequestContext.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/OpaqueStream.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/Request.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/RequestContext.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/RequestHeaders.Generated.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/RequestHeaders.Generated.tt (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/RequestHeaders.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/RequestStream.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/RequestUriBuilder.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/Response.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/ResponseStream.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/ResponseStreamAsyncResult.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/RequestProcessing/SslStatus.cs (96%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/Resources.Designer.cs (97%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/Resources.resx (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/TimeoutManager.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/UrlPrefix.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/ValidationHelper.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/WebListener.cs (99%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/WebListenerException.cs (98%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/fx/System/Diagnostics/TraceEventType.cs (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/fx/System/ExternDll.cs (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/fx/System/Runtime/InteropServices/ExternalException.cs (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/fx/System/SafeNativeMethods.cs (100%) rename src/{Microsoft.Net.Server => Microsoft.Net.Http.Server}/project.json (100%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/AuthenticationTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/HttpsTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj => Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj} (100%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/OpaqueUpgradeTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/RequestBodyTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/RequestHeaderTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/RequestTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/ResponseBodyTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/ResponseHeaderTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/ResponseSendFileTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/ResponseTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/ServerTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/Utilities.cs (98%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/WebSocketTests.cs (99%) rename test/{Microsoft.Net.Server.FunctionalTests => Microsoft.Net.Http.Server.FunctionalTests}/project.json (89%) diff --git a/WebListener.sln b/WebListener.sln index 3846c0df71..a27e04c6b7 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.21730.1 +VisualStudioVersion = 14.0.21916.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -11,7 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E183C826-1 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A1E31E3-2794-4CA3-B8E2-253E96BDE514}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Server", "src\Microsoft.Net.Server\Microsoft.Net.Server.kproj", "{3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server", "src\Microsoft.Net.Http.Server\Microsoft.Net.Http.Server.kproj", "{3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\HelloWorld\HelloWorld.kproj", "{6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}" EndProject @@ -25,7 +25,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.Web EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.kproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Server.FunctionalTests", "test\Microsoft.Net.Server.FunctionalTests\Microsoft.Net.Server.FunctionalTests.kproj", "{DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server.FunctionalTests", "test\Microsoft.Net.Http.Server.FunctionalTests\Microsoft.Net.Http.Server.FunctionalTests.kproj", "{DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5E9B546C-17AC-4BDF-BCB3-5955D4755ED8}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 243af9a49d..e693458753 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -20,7 +20,7 @@ using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; namespace HelloWorld { diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 8bf9217d36..3a1514068e 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.Net.Server" : "" + "Microsoft.Net.Http.Server" : "" }, "frameworks": { "net45": { }, diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 917c06a5b7..1956abba60 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -23,7 +23,7 @@ using Microsoft.AspNet; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Server.WebListener; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; namespace SelfHostServer { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index bee846ffc4..6bab457b0b 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -3,7 +3,7 @@ "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "", - "Microsoft.Net.Server": "" + "Microsoft.Net.Http.Server": "" }, "commands": { "web": "Microsoft.AspNet.Hosting --server=Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:8080" }, "frameworks": { diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index e86419c1c5..272134c0fe 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -27,7 +27,7 @@ using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNet.HttpFeature.Security; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 9a5023f9b2..d27fb974da 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -28,7 +28,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.HttpFeature.Security; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; using Microsoft.Net.WebSockets; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index f1de9d6423..c02513be2f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -20,7 +20,7 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; using Microsoft.Framework.Logging; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { @@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Server.WebListener { private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; - private readonly Microsoft.Net.Server.WebListener _listener; + private readonly Microsoft.Net.Http.Server.WebListener _listener; private readonly ILogger _logger; private AppFunc _appFunc; @@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Server.WebListener // TODO: private IDictionary _capabilities; - internal MessagePump(Microsoft.Net.Server.WebListener listener, ILoggerFactory loggerFactory) + internal MessagePump(Microsoft.Net.Http.Server.WebListener listener, ILoggerFactory loggerFactory) { Contract.Assert(listener != null); _listener = listener; @@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Server.WebListener _shutdownSignal = new ManualResetEvent(false); } - internal Microsoft.Net.Server.WebListener Listener + internal Microsoft.Net.Http.Server.WebListener Listener { get { return _listener; } } diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index a5a80ecce4..803beae3af 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -43,7 +43,7 @@ using Microsoft.AspNet.Http; using Microsoft.AspNet.Hosting.Server; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.Logging; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { @@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Server.WebListener [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] public IServerInformation Initialize(IConfiguration configuration) { - Microsoft.Net.Server.WebListener listener = new Microsoft.Net.Server.WebListener(); + Microsoft.Net.Http.Server.WebListener listener = new Microsoft.Net.Http.Server.WebListener(); ParseAddresses(configuration, listener); return new ServerInformation(new MessagePump(listener, _loggerFactory)); } @@ -101,7 +101,7 @@ namespace Microsoft.AspNet.Server.WebListener return serverInfo.MessagePump; } - private void ParseAddresses(IConfiguration config, Microsoft.Net.Server.WebListener listener) + private void ParseAddresses(IConfiguration config, Microsoft.Net.Http.Server.WebListener listener) { // TODO: Key format? string urls; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs index ef9e0bdda1..314b60e336 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Server.WebListener get { return GetType().GetTypeInfo().Assembly.GetName().Name; } } - public Microsoft.Net.Server.WebListener Listener + public Microsoft.Net.Http.Server.WebListener Listener { get { return _messagePump.Listener; } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index d7c511301b..2ee44e51cb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -6,7 +6,7 @@ "Microsoft.AspNet.HttpFeature": "1.0.0-*", "Microsoft.Framework.ConfigurationModel": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", - "Microsoft.Net.Server" : "", + "Microsoft.Net.Http.Server" : "", "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" }, "compilationOptions": { diff --git a/src/Microsoft.Net.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs similarity index 99% rename from src/Microsoft.Net.Server/AsyncAcceptContext.cs rename to src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs index f1df0bbbad..08edc569ac 100644 --- a/src/Microsoft.Net.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs @@ -27,7 +27,7 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal unsafe class AsyncAcceptContext : IAsyncResult, IDisposable { diff --git a/src/Microsoft.Net.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs similarity index 99% rename from src/Microsoft.Net.Server/AuthenticationManager.cs rename to src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 458b46261d..4d88e5716a 100644 --- a/src/Microsoft.Net.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -29,7 +29,7 @@ using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Principal; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // See the native HTTP_SERVER_AUTHENTICATION_INFO structure documentation for additional information. // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364638(v=vs.85).aspx diff --git a/src/Microsoft.Net.Server/AuthenticationTypes.cs b/src/Microsoft.Net.Http.Server/AuthenticationTypes.cs similarity index 96% rename from src/Microsoft.Net.Server/AuthenticationTypes.cs rename to src/Microsoft.Net.Http.Server/AuthenticationTypes.cs index 9906ba2053..a7c39ab7c2 100644 --- a/src/Microsoft.Net.Server/AuthenticationTypes.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationTypes.cs @@ -17,7 +17,7 @@ using System; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { [Flags] public enum AuthenticationTypes diff --git a/src/Microsoft.Net.Server/Constants.cs b/src/Microsoft.Net.Http.Server/Constants.cs similarity index 99% rename from src/Microsoft.Net.Server/Constants.cs rename to src/Microsoft.Net.Http.Server/Constants.cs index a85d13c4ae..2d8ae594ab 100644 --- a/src/Microsoft.Net.Server/Constants.cs +++ b/src/Microsoft.Net.Http.Server/Constants.cs @@ -23,7 +23,7 @@ using System; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class Constants { diff --git a/src/Microsoft.Net.Server/CustomDictionary.xml b/src/Microsoft.Net.Http.Server/CustomDictionary.xml similarity index 100% rename from src/Microsoft.Net.Server/CustomDictionary.xml rename to src/Microsoft.Net.Http.Server/CustomDictionary.xml diff --git a/src/Microsoft.Net.Server/GlobalSuppressions.cs b/src/Microsoft.Net.Http.Server/GlobalSuppressions.cs similarity index 100% rename from src/Microsoft.Net.Server/GlobalSuppressions.cs rename to src/Microsoft.Net.Http.Server/GlobalSuppressions.cs diff --git a/src/Microsoft.Net.Server/Helpers.cs b/src/Microsoft.Net.Http.Server/Helpers.cs similarity index 97% rename from src/Microsoft.Net.Server/Helpers.cs rename to src/Microsoft.Net.Http.Server/Helpers.cs index 754acbda8c..60dad126ec 100644 --- a/src/Microsoft.Net.Server/Helpers.cs +++ b/src/Microsoft.Net.Http.Server/Helpers.cs @@ -24,7 +24,7 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class Helpers { diff --git a/src/Microsoft.Net.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs similarity index 98% rename from src/Microsoft.Net.Server/LogHelper.cs rename to src/Microsoft.Net.Http.Server/LogHelper.cs index 5b7efd1830..01501b4607 100644 --- a/src/Microsoft.Net.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Globalization; using Microsoft.Framework.Logging; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class LogHelper { diff --git a/src/Microsoft.Net.Server/Microsoft.Net.Server.kproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj similarity index 100% rename from src/Microsoft.Net.Server/Microsoft.Net.Server.kproj rename to src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj diff --git a/src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs b/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs similarity index 99% rename from src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs index 1b501e5cad..c1c6def0cf 100644 --- a/src/Microsoft.Net.Server/NativeInterop/AddressFamily.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { /// /// diff --git a/src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs similarity index 97% rename from src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index 7d99de7dcf..5d78b9a498 100644 --- a/src/Microsoft.Net.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -23,7 +23,7 @@ using System; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class ComNetOS { diff --git a/src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs index 6ee9ea9742..2964b40da6 100644 --- a/src/Microsoft.Net.Server/NativeInterop/ContextAttribute.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs @@ -21,7 +21,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal enum ContextAttribute { diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs similarity index 97% rename from src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs index b2ffd71a52..bcf8890704 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpRequestQueueV2Handle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs @@ -23,7 +23,7 @@ using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // This class is a wrapper for Http.sys V2 request queue handle. internal sealed class HttpRequestQueueV2Handle : SafeHandleZeroOrMinusOneIsInvalid diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs index 203785315e..6300ef684b 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpServerSessionHandle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs @@ -25,7 +25,7 @@ using System; using System.Threading; using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal sealed class HttpServerSessionHandle : CriticalHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs index bb8ddc3848..436a993cfd 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpSysRequestHeader.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal enum HttpSysRequestHeader { diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs index b996342215..570a7928ea 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpSysResponseHeader.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal enum HttpSysResponseHeader { diff --git a/src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs similarity index 99% rename from src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs index 549c63ecb0..94d60a3abb 100644 --- a/src/Microsoft.Net.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs @@ -30,7 +30,7 @@ using System.Security; using Microsoft.Win32; #endif -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class HttpSysSettings { diff --git a/src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs b/src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs similarity index 97% rename from src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs index bf752ab2e2..d3594b3deb 100644 --- a/src/Microsoft.Net.Server/NativeInterop/IntPtrHelper.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs @@ -23,7 +23,7 @@ using System; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class IntPtrHelper { diff --git a/src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs similarity index 97% rename from src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs index f0adc64e05..e5934498d9 100644 --- a/src/Microsoft.Net.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs @@ -23,7 +23,7 @@ using System; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class NclUtilities { diff --git a/src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs similarity index 97% rename from src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs index 1dac268c56..3c9bf9d67f 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SSPIHandle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs @@ -24,7 +24,7 @@ using System; using System.Runtime.InteropServices; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct SSPIHandle diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs index 7a24acf6dd..7b996d37fa 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLoadLibrary.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs @@ -23,7 +23,7 @@ using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs index eea727e5fb..886381465b 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFree.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs @@ -24,7 +24,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs index be210bbdf1..8a08e20b85 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLocalFreeChannelBinding.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -24,7 +24,7 @@ using System; using System.Security.Authentication.ExtendedProtection; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal class SafeLocalFreeChannelBinding : ChannelBinding { diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs similarity index 97% rename from src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs index daa501bbc1..d961d1d38b 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeLocalMemHandle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs @@ -24,7 +24,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs index fb4f32484b..cf8d1f38e4 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs @@ -25,7 +25,7 @@ using System; using System.Runtime.InteropServices; using System.Threading; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal class SafeNativeOverlapped : SafeHandle { diff --git a/src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs index 8b2acabade..9787a24066 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SchProtocols.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { using System; using System.Globalization; diff --git a/src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs similarity index 98% rename from src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs index 59ea71a2ea..aaafb59294 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SecurityStatus.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs @@ -21,7 +21,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal enum SecurityStatus { diff --git a/src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs similarity index 99% rename from src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs index 0a59d72f45..4d633452ac 100644 --- a/src/Microsoft.Net.Server/NativeInterop/SocketAddress.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs @@ -28,7 +28,7 @@ using System.Globalization; using System.Net; using System.Text; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // a little perf app measured these times when comparing the internal // buffer implemented as a managed byte[] or unmanaged memory IntPtr diff --git a/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs similarity index 99% rename from src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs rename to src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index acf409ed44..641b25e963 100644 --- a/src/Microsoft.Net.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -26,7 +26,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class UnsafeNclNativeMethods { @@ -80,7 +80,7 @@ namespace Microsoft.Net.Server [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] internal static extern unsafe uint HttpCreateRequestQueue(HttpApi.HTTPAPI_VERSION version, string pName, - Microsoft.Net.Server.UnsafeNclNativeMethods.SECURITY_ATTRIBUTES pSecurityAttributes, uint flags, out HttpRequestQueueV2Handle pReqQueueHandle); + Microsoft.Net.Http.Server.UnsafeNclNativeMethods.SECURITY_ATTRIBUTES pSecurityAttributes, uint flags, out HttpRequestQueueV2Handle pReqQueueHandle); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); diff --git a/src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs similarity index 97% rename from src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs index a398747bba..b45b24b658 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/BoundaryType.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs @@ -21,7 +21,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal enum BoundaryType { diff --git a/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs index 3f6228db45..5e9d078df6 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs @@ -31,7 +31,7 @@ using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // This class is used to load the client certificate on-demand. Because client certs are optional, all // failures are handled internally and reported via ClientCertException or ClientCertError. diff --git a/src/Microsoft.Net.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/HeaderCollection.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs index 62a800cd71..52eaa6e33b 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs @@ -5,7 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class HeaderCollection : IDictionary { diff --git a/src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs index 4cc96769b7..9b3726be86 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HeaderEncoding.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs @@ -26,7 +26,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // we use this static class as a helper class to encode/decode HTTP headers. // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF diff --git a/src/Microsoft.Net.Server/RequestProcessing/HeaderParser.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs similarity index 98% rename from src/Microsoft.Net.Server/RequestProcessing/HeaderParser.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs index fb217f06b1..ebc77b8203 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HeaderParser.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class HeaderParser { diff --git a/src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs index 3aaa743291..0da9062d6e 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HttpKnownHeaderNames.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs @@ -21,7 +21,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class HttpKnownHeaderNames { diff --git a/src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs index 5b9596603f..a31b24985d 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HttpReasonPhrase.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs @@ -21,7 +21,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class HttpReasonPhrase { diff --git a/src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs index a8535a1951..3a84ed8f22 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/HttpStatusCode.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // Redirect Status code numbers that need to be defined. diff --git a/src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 74afb31713..61f81ebe8c 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal unsafe class NativeRequestContext : IDisposable { diff --git a/src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs index 6f33ea51d8..8c66cbca9a 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs @@ -26,7 +26,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // A duplex wrapper around RequestStream and ResponseStream. // TODO: Consider merging RequestStream and ResponseStream instead. diff --git a/src/Microsoft.Net.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/Request.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 4e05202106..daf92329ed 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -35,7 +35,7 @@ using System.Security.Principal; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public sealed class Request { diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 98b9c99cb6..5a47b0498c 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -33,7 +33,7 @@ using System.Threading.Tasks; using Microsoft.Framework.Logging; using Microsoft.Net.WebSockets; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public sealed class RequestContext : IDisposable { diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs index bacf8811a7..66019a500e 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs @@ -30,7 +30,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class RequestHeaders diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.tt b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.tt rename to src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt index 6545fffe44..931380b1fd 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.Generated.tt +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt @@ -69,7 +69,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class RequestHeaders diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs index 113f5bc3fd..95e754870a 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs @@ -40,7 +40,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal partial class RequestHeaders : IDictionary { diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 40f6e507f3..fb93d95eb3 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal class RequestStream : Stream { diff --git a/src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 5127f81281..6fd6467468 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -27,7 +27,7 @@ using System.Diagnostics; using System.Globalization; using System.Text; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // We don't use the cooked URL because http.sys unescapes all percent-encoded values. However, // we also can't just use the raw Uri, since http.sys supports not only Utf-8, but also ANSI/DBCS and diff --git a/src/Microsoft.Net.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/Response.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index ec5eeecbf4..95193ca2bb 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -31,7 +31,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public sealed unsafe class Response { diff --git a/src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 5f13a2aaf8..61825d7d73 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -29,7 +29,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal class ResponseStream : Stream { diff --git a/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs similarity index 99% rename from src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index b771b7b88d..883459d132 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal unsafe class ResponseStreamAsyncResult : IAsyncResult, IDisposable { diff --git a/src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs similarity index 96% rename from src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs index 056c9e61cb..a974c723e5 100644 --- a/src/Microsoft.Net.Server/RequestProcessing/SslStatus.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs @@ -21,7 +21,7 @@ // // ----------------------------------------------------------------------- -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal enum SslStatus : byte { diff --git a/src/Microsoft.Net.Server/Resources.Designer.cs b/src/Microsoft.Net.Http.Server/Resources.Designer.cs similarity index 97% rename from src/Microsoft.Net.Server/Resources.Designer.cs rename to src/Microsoft.Net.Http.Server/Resources.Designer.cs index 9fdfa80837..0d5dffd0c3 100644 --- a/src/Microsoft.Net.Server/Resources.Designer.cs +++ b/src/Microsoft.Net.Http.Server/Resources.Designer.cs @@ -25,7 +25,7 @@ // //------------------------------------------------------------------------------ -namespace Microsoft.Net.Server { +namespace Microsoft.Net.Http.Server { using System; @@ -56,7 +56,7 @@ namespace Microsoft.Net.Server { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Net.Server.Resources", System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Resources)).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Net.Http.Server.Resources", System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Resources)).Assembly); resourceMan = temp; } return resourceMan; diff --git a/src/Microsoft.Net.Server/Resources.resx b/src/Microsoft.Net.Http.Server/Resources.resx similarity index 100% rename from src/Microsoft.Net.Server/Resources.resx rename to src/Microsoft.Net.Http.Server/Resources.resx diff --git a/src/Microsoft.Net.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs similarity index 99% rename from src/Microsoft.Net.Server/TimeoutManager.cs rename to src/Microsoft.Net.Http.Server/TimeoutManager.cs index 6789328c1f..e7bd3b2236 100644 --- a/src/Microsoft.Net.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -25,7 +25,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { // See the native HTTP_TIMEOUT_LIMIT_INFO structure documentation for additional information. // http://msdn.microsoft.com/en-us/library/aa364661.aspx diff --git a/src/Microsoft.Net.Server/UrlPrefix.cs b/src/Microsoft.Net.Http.Server/UrlPrefix.cs similarity index 99% rename from src/Microsoft.Net.Server/UrlPrefix.cs rename to src/Microsoft.Net.Http.Server/UrlPrefix.cs index 0d1e732bef..24cf55fd0e 100644 --- a/src/Microsoft.Net.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefix.cs @@ -24,7 +24,7 @@ using System; using System.Globalization; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class UrlPrefix { diff --git a/src/Microsoft.Net.Server/ValidationHelper.cs b/src/Microsoft.Net.Http.Server/ValidationHelper.cs similarity index 98% rename from src/Microsoft.Net.Server/ValidationHelper.cs rename to src/Microsoft.Net.Http.Server/ValidationHelper.cs index ad5ab47d99..fc84aa1ecd 100644 --- a/src/Microsoft.Net.Server/ValidationHelper.cs +++ b/src/Microsoft.Net.Http.Server/ValidationHelper.cs @@ -24,7 +24,7 @@ using System; using System.Globalization; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class ValidationHelper { diff --git a/src/Microsoft.Net.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs similarity index 99% rename from src/Microsoft.Net.Server/WebListener.cs rename to src/Microsoft.Net.Http.Server/WebListener.cs index 66a38efdfc..d8d80772dc 100644 --- a/src/Microsoft.Net.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -34,7 +34,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Framework.Logging; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { using AppFunc = Func; diff --git a/src/Microsoft.Net.Server/WebListenerException.cs b/src/Microsoft.Net.Http.Server/WebListenerException.cs similarity index 98% rename from src/Microsoft.Net.Server/WebListenerException.cs rename to src/Microsoft.Net.Http.Server/WebListenerException.cs index c9d17fca6b..a47346c509 100644 --- a/src/Microsoft.Net.Server/WebListenerException.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerException.cs @@ -26,7 +26,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] public class WebListenerException : Win32Exception diff --git a/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs similarity index 100% rename from src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs rename to src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs diff --git a/src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs similarity index 100% rename from src/Microsoft.Net.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs rename to src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs diff --git a/src/Microsoft.Net.Server/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs similarity index 100% rename from src/Microsoft.Net.Server/fx/System/Diagnostics/TraceEventType.cs rename to src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs diff --git a/src/Microsoft.Net.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs similarity index 100% rename from src/Microsoft.Net.Server/fx/System/ExternDll.cs rename to src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs diff --git a/src/Microsoft.Net.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs similarity index 100% rename from src/Microsoft.Net.Server/fx/System/Runtime/InteropServices/ExternalException.cs rename to src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs diff --git a/src/Microsoft.Net.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs similarity index 100% rename from src/Microsoft.Net.Server/fx/System/SafeNativeMethods.cs rename to src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs diff --git a/src/Microsoft.Net.Server/project.json b/src/Microsoft.Net.Http.Server/project.json similarity index 100% rename from src/Microsoft.Net.Server/project.json rename to src/Microsoft.Net.Http.Server/project.json diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index acb4313ea1..3f40f1cbdc 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -22,7 +22,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.PipelineCore; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 1cd71e5a03..8a4efdc974 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -23,7 +23,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 16c9cfa70a..337b2359d4 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -27,7 +27,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.PipelineCore; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index 3181a39875..5315a6952f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -17,7 +17,7 @@ using System; using System.Threading.Tasks; -using Microsoft.Net.Server; +using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index e93d53e995..cd4dec25c2 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -11,7 +11,7 @@ "Microsoft.AspNet.Server.WebListener" : "", "Microsoft.Framework.ConfigurationModel": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", - "Microsoft.Net.Server" : "", + "Microsoft.Net.Http.Server" : "", "Xunit.KRunner": "1.0.0-*" }, "frameworks": { diff --git a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 6c7474f234..09f501fa24 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -6,7 +6,7 @@ using System.Net.Http; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class AuthenticationTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index cf7aa0296a..4822827bd6 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class HttpsTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj similarity index 100% rename from test/Microsoft.Net.Server.FunctionalTests/Microsoft.Net.Server.FunctionalTests.kproj rename to test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj diff --git a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index 48bcc03ba2..e3076cff0f 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -8,7 +8,7 @@ using System.Text; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class OpaqueUpgradeTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index 89e24a90c1..eddb4388d4 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class RequestBodyTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index 3fb03df524..73eb3d152e 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -8,7 +8,7 @@ using System.Text; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class RequestHeaderTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index cf8205c18e..de9616280b 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class RequestTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 299f719f5c..bd9ab9bf0f 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class ResponseBodyTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index ab12512b17..8b0dad5460 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -7,7 +7,7 @@ using System.Net.Http; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class ResponseHeaderTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index 5139d9ad40..f13af46cf1 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class ResponseSendFileTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs index f5d5c2146c..4e46f19ef7 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs @@ -6,7 +6,7 @@ using System.Net.Http; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class ResponseTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index af97555358..50b325c003 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class ServerTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs similarity index 98% rename from test/Microsoft.Net.Server.FunctionalTests/Utilities.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs index 18c3d31987..8e8fdf16d7 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs @@ -2,7 +2,7 @@ using System; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { internal static class Utilities { diff --git a/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs similarity index 99% rename from test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs rename to test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index e54c94740f..54e5a2a16c 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -namespace Microsoft.Net.Server +namespace Microsoft.Net.Http.Server { public class WebSocketTests { diff --git a/test/Microsoft.Net.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json similarity index 89% rename from test/Microsoft.Net.Server.FunctionalTests/project.json rename to test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 1c3855abb0..31d057271a 100644 --- a/test/Microsoft.Net.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -3,7 +3,7 @@ "test": "Xunit.KRunner" }, "dependencies": { - "Microsoft.Net.Server" : "", + "Microsoft.Net.Http.Server" : "", "Xunit.KRunner": "1.0.0-*" }, "frameworks": { From 47a0530cc409e0127f102b72753e0c0092f542b5 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 15 Aug 2014 09:38:17 -0700 Subject: [PATCH 097/597] Removed source files from the project --- samples/HelloWorld/HelloWorld.kproj | 9 +-- samples/SelfHostServer/SelfHostServer.kproj | 11 +-- .../Microsoft.AspNet.Security.Windows.kproj | 55 +-------------- .../Microsoft.AspNet.Server.WebListener.kproj | 17 +---- .../Microsoft.Net.Http.Server.kproj | 67 ------------------- .../Microsoft.Net.WebSockets.kproj | 27 -------- ...t.Server.WebListener.FunctionalTests.kproj | 18 ----- ...soft.Net.Http.Server.FunctionalTests.kproj | 18 ----- 8 files changed, 4 insertions(+), 218 deletions(-) diff --git a/samples/HelloWorld/HelloWorld.kproj b/samples/HelloWorld/HelloWorld.kproj index d0e521b2a1..cad0b80483 100644 --- a/samples/HelloWorld/HelloWorld.kproj +++ b/samples/HelloWorld/HelloWorld.kproj @@ -16,12 +16,5 @@ 2.0 - - - - - - - - + \ No newline at end of file diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index 27e7adbaef..efbadb0189 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -19,14 +19,5 @@ 57504 - - - - - - - - - - + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj index 3c5c6aba75..5e97f1a4bf 100644 --- a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj +++ b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj @@ -17,58 +17,5 @@ 2.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj index b3e1459db4..72e20d0eb5 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -16,20 +16,5 @@ 2.0 - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj index 7ef3155968..57ece075d0 100644 --- a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj +++ b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj @@ -17,72 +17,5 @@ 2.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj index 0d270aef1d..e3d0679128 100644 --- a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj +++ b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj @@ -17,32 +17,5 @@ 2.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj index 93e75d54f4..4c049bd5dc 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj @@ -17,23 +17,5 @@ 2.0 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj index a579d02c1f..5f105dd1f6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj @@ -17,23 +17,5 @@ 2.0 - - - - - - - - - - - - - - - - - - \ No newline at end of file From d0b9d5c579b09f4e0aee9559d3982c42f27b7fcb Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 18 Aug 2014 15:10:56 -0700 Subject: [PATCH 098/597] Reacting to System.IO.FileSystem package version change --- samples/SelfHostServer/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 6bab457b0b..48fe41184a 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -17,7 +17,7 @@ "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", - "System.IO.FileSystem": "4.0.10.0", + "System.IO.FileSystem": "4.0.0.0", "System.Linq": "4.0.0.0", "System.Reflection": "4.0.10.0", "System.Resources.ResourceManager": "4.0.0.0", diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 1c2d1ea7f0..29fbbceb06 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -20,7 +20,7 @@ "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", "System.IO": "4.0.0.0", - "System.IO.FileSystem": "4.0.10.0", + "System.IO.FileSystem": "4.0.0.0", "System.Linq": "4.0.0.0", "System.Net.Primitives": "4.0.10.0", "System.Reflection": "4.0.10.0", From dbf13614da99540a76687635096a5420ea9503b4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 20 Aug 2014 06:56:39 -0700 Subject: [PATCH 099/597] Reacting to System.IO package version change --- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- src/Microsoft.Net.WebSockets/project.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 48fe41184a..bd23b22505 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -16,7 +16,7 @@ "System.Diagnostics.Debug": "4.0.10.0", "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", - "System.IO": "4.0.0.0", + "System.IO": "4.0.10.0", "System.IO.FileSystem": "4.0.0.0", "System.Linq": "4.0.0.0", "System.Reflection": "4.0.10.0", diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 2ee44e51cb..50b13d703d 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -23,7 +23,7 @@ "System.Diagnostics.Debug": "4.0.10.0", "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", - "System.IO": "4.0.0.0", + "System.IO": "4.0.10.0", "System.Linq": "4.0.0.0", "System.Net.Primitives": "4.0.10.0", "System.Reflection": "4.0.10.0", diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 29fbbceb06..a6ffbe5438 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -19,7 +19,7 @@ "System.Diagnostics.Debug": "4.0.10.0", "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", - "System.IO": "4.0.0.0", + "System.IO": "4.0.10.0", "System.IO.FileSystem": "4.0.0.0", "System.Linq": "4.0.0.0", "System.Net.Primitives": "4.0.10.0", diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 1a18c457ba..0a52489089 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -15,7 +15,7 @@ "System.Diagnostics.Debug": "4.0.10.0", "System.Diagnostics.Tools": "4.0.0.0", "System.Globalization": "4.0.10.0", - "System.IO": "4.0.0.0", + "System.IO": "4.0.10.0", "System.Linq": "4.0.0.0", "System.Net.Primitives": "4.0.10.0", "System.Reflection": "4.0.10.0", From 5de55349827a362c7d537770ce34752f3a46f5ef Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 8 Aug 2014 14:57:21 -0700 Subject: [PATCH 100/597] #43 - Honor CancellationTokens for Read/Write/Flush/SendFileAsync. --- src/Microsoft.Net.Http.Server/Helpers.cs | 7 + .../RequestProcessing/RequestContext.cs | 8 + .../RequestProcessing/RequestStream.cs | 22 ++- .../RequestProcessing/ResponseStream.cs | 48 ++++-- .../ResponseStreamAsyncResult.cs | 16 +- .../RequestBodyTests.cs | 151 ++++++++++++++++++ .../ResponseBodyTests.cs | 88 ++++++++++ 7 files changed, 323 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/Helpers.cs b/src/Microsoft.Net.Http.Server/Helpers.cs index 60dad126ec..a8e0a2e5a9 100644 --- a/src/Microsoft.Net.Http.Server/Helpers.cs +++ b/src/Microsoft.Net.Http.Server/Helpers.cs @@ -33,6 +33,13 @@ namespace Microsoft.Net.Http.Server return Task.FromResult(null); } + internal static Task CancelledTask() + { + TaskCompletionSource tcs = new TaskCompletionSource(); + tcs.TrySetCanceled(); + return tcs.Task; + } + internal static ConfiguredTaskAwaitable SupressContext(this Task task) { return task.ConfigureAwait(continueOnCapturedContext: false); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 5a47b0498c..0c3ea2baf4 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -37,6 +37,8 @@ namespace Microsoft.Net.Http.Server { public sealed class RequestContext : IDisposable { + internal static Action AbortDelegate = Abort; + private WebListener _server; private Request _request; private Response _response; @@ -403,6 +405,12 @@ namespace Microsoft.Net.Http.Server _request.Dispose(); } + private static void Abort(object state) + { + var context = (RequestContext)state; + context.Abort(); + } + // This is only called while processing incoming requests. We don't have to worry about cancelling // any response writes. [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index fb93d95eb3..aed48a5383 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -319,8 +319,10 @@ namespace Microsoft.Net.Http.Server return Task.FromResult(0); } - // TODO: Needs full cancellation integration - cancellationToken.ThrowIfCancellationRequested(); + if (cancellationToken.IsCancellationRequested) + { + return Helpers.CancelledTask(); + } // TODO: Verbose log parameters RequestStreamAsyncResult asyncResult = null; @@ -349,7 +351,13 @@ namespace Microsoft.Net.Http.Server size = MaxReadSize; } - asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead); + CancellationTokenRegistration cancellationRegistration; + if (cancellationToken.CanBeCanceled) + { + cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + } + + asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration); uint bytesReturned; try @@ -449,6 +457,7 @@ namespace Microsoft.Net.Http.Server private TaskCompletionSource _tcs; private RequestStream _requestStream; private AsyncCallback _callback; + private CancellationTokenRegistration _cancellationRegistration; internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback) { @@ -464,6 +473,11 @@ namespace Microsoft.Net.Http.Server } internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead) + : this(requestStream, userState, callback, buffer, offset, dataAlreadyRead, new CancellationTokenRegistration()) + { + } + + internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead, CancellationTokenRegistration cancellationRegistration) : this(requestStream, userState, callback) { _dataAlreadyRead = dataAlreadyRead; @@ -471,6 +485,7 @@ namespace Microsoft.Net.Http.Server overlapped.AsyncResult = this; _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, buffer)); _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); + _cancellationRegistration = cancellationRegistration; } internal RequestStream RequestStream @@ -583,6 +598,7 @@ namespace Microsoft.Net.Http.Server { _overlapped.Dispose(); } + _cancellationRegistration.Dispose(); } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 61825d7d73..ce086c4ca0 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -135,12 +135,20 @@ namespace Microsoft.Net.Http.Server UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); // TODO: Verbose log - // TODO: Real cancellation - cancellationToken.ThrowIfCancellationRequested(); + if (cancellationToken.IsCancellationRequested) + { + return Helpers.CancelledTask(); + } + + CancellationTokenRegistration cancellationRegistration; + if (cancellationToken.CanBeCanceled) + { + cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + } // TODO: Don't add MoreData flag if content-length == 0? flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, null, 0, 0, _requestContext.Response.BoundaryType == BoundaryType.Chunked, false); + ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, null, 0, 0, _requestContext.Response.BoundaryType == BoundaryType.Chunked, false, cancellationRegistration); try { @@ -492,7 +500,7 @@ namespace Microsoft.Net.Http.Server } } - public override unsafe Task WriteAsync(byte[] buffer, int offset, int size, CancellationToken cancel) + public override unsafe Task WriteAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken) { if (buffer == null) { @@ -521,14 +529,22 @@ namespace Microsoft.Net.Http.Server } // TODO: Verbose log - // TODO: Real cancelation - cancel.ThrowIfCancellationRequested(); + if (cancellationToken.IsCancellationRequested) + { + return Helpers.CancelledTask(); + } + + CancellationTokenRegistration cancellationRegistration; + if (cancellationToken.CanBeCanceled) + { + cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + } uint statusCode; uint bytesSent = 0; flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; bool sentHeaders = _requestContext.Response.SentHeaders; - ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, buffer, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders); + ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, buffer, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, cancellationRegistration); // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite. UpdateWritenCount((uint)((_requestContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size)); @@ -597,7 +613,7 @@ namespace Microsoft.Net.Http.Server return asyncResult.Task; } - internal unsafe Task SendFileAsync(string fileName, long offset, long? size, CancellationToken cancel) + internal unsafe Task SendFileAsync(string fileName, long offset, long? size, CancellationToken cancellationToken) { // It's too expensive to validate the file attributes before opening the file. Open the file and then check the lengths. // This all happens inside of ResponseStreamAsyncResult. @@ -610,9 +626,6 @@ namespace Microsoft.Net.Http.Server throw new ObjectDisposedException(GetType().FullName); } - // TODO: Real cancellation - cancel.ThrowIfCancellationRequested(); - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); if (size == 0 && _leftToWrite != 0) { @@ -624,12 +637,23 @@ namespace Microsoft.Net.Http.Server } // TODO: Verbose log + if (cancellationToken.IsCancellationRequested) + { + return Helpers.CancelledTask(); + } + + CancellationTokenRegistration cancellationRegistration; + if (cancellationToken.CanBeCanceled) + { + cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + } + uint statusCode; uint bytesSent = 0; flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; bool sentHeaders = _requestContext.Response.SentHeaders; ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, fileName, offset, size, - _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders); + _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, cancellationRegistration); long bytesWritten; if (_requestContext.Response.BoundaryType == BoundaryType.Chunked) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 883459d132..6c829cddba 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -43,6 +43,7 @@ namespace Microsoft.Net.Http.Server private TaskCompletionSource _tcs; private AsyncCallback _callback; private uint _bytesSent; + private CancellationTokenRegistration _cancellationRegistration; internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback) { @@ -50,12 +51,20 @@ namespace Microsoft.Net.Http.Server _tcs = new TaskCompletionSource(userState); _callback = callback; } - internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback, byte[] buffer, int offset, int size, bool chunked, bool sentHeaders) + : this(responseStream, userState, callback, buffer, offset, size, chunked, sentHeaders, + new CancellationTokenRegistration()) + { + } + + internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback, + byte[] buffer, int offset, int size, bool chunked, bool sentHeaders, + CancellationTokenRegistration cancellationRegistration) : this(responseStream, userState, callback) { _sentHeaders = sentHeaders; + _cancellationRegistration = cancellationRegistration; Overlapped overlapped = new Overlapped(); overlapped.AsyncResult = this; @@ -121,10 +130,12 @@ namespace Microsoft.Net.Http.Server } internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback, - string fileName, long offset, long? size, bool chunked, bool sentHeaders) + string fileName, long offset, long? size, bool chunked, bool sentHeaders, + CancellationTokenRegistration cancellationRegistration) : this(responseStream, userState, callback) { _sentHeaders = sentHeaders; + _cancellationRegistration = cancellationRegistration; Overlapped overlapped = new Overlapped(); overlapped.AsyncResult = this; @@ -449,6 +460,7 @@ namespace Microsoft.Net.Http.Server { _fileStream.Dispose(); } + _cancellationRegistration.Dispose(); } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index eddb4388d4..47dfbcb117 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -168,6 +168,156 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task RequestBody_ReadAsyncAlreadyCancelled_ReturnsCanceledTask() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address, "Hello World"); + + var context = await server.GetContextAsync(); + + byte[] input = new byte[10]; + var cts = new CancellationTokenSource(); + cts.Cancel(); + + Task task = context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.True(task.IsCanceled); + + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestBody_ReadAsyncPartialBodyWithCancellationToken_Success() + { + StaggardContent content = new StaggardContent(); + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address, content); + + var context = await server.GetContextAsync(); + byte[] input = new byte[10]; + var cts = new CancellationTokenSource(); + int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.Equal(5, read); + content.Block.Release(); + read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.Equal(5, read); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestBody_ReadAsyncPartialBodyWithTimeout_Success() + { + StaggardContent content = new StaggardContent(); + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address, content); + + var context = await server.GetContextAsync(); + byte[] input = new byte[10]; + var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(5)); + int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.Equal(5, read); + content.Block.Release(); + read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.Equal(5, read); + context.Dispose(); + + string response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task RequestBody_ReadAsyncPartialBodyAndCancel_Canceled() + { + StaggardContent content = new StaggardContent(); + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address, content); + + var context = await server.GetContextAsync(); + byte[] input = new byte[10]; + var cts = new CancellationTokenSource(); + int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.Equal(5, read); + var readTask = context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.False(readTask.IsCanceled); + cts.Cancel(); + await Assert.ThrowsAsync(async () => await readTask); + content.Block.Release(); + context.Dispose(); + + await Assert.ThrowsAsync(async () => await responseTask); + } + } + + [Fact] + public async Task RequestBody_ReadAsyncPartialBodyAndExpiredTimeout_Canceled() + { + StaggardContent content = new StaggardContent(); + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address, content); + + var context = await server.GetContextAsync(); + byte[] input = new byte[10]; + var cts = new CancellationTokenSource(); + int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.Equal(5, read); + cts.CancelAfter(TimeSpan.FromMilliseconds(100)); + var readTask = context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); + Assert.False(readTask.IsCanceled); + await Assert.ThrowsAsync(async () => await readTask); + content.Block.Release(); + context.Dispose(); + + await Assert.ThrowsAsync(async () => await responseTask); + } + } + + // Make sure that using our own disconnect token as a read cancellation token doesn't + // cause recursion problems when it fires and calls Abort. + [Fact] + public async Task RequestBody_ReadAsyncPartialBodyAndDisconnectedClient_Canceled() + { + StaggardContent content = new StaggardContent(); + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var client = new HttpClient(); + var responseTask = client.PostAsync(address, content); + + var context = await server.GetContextAsync(); + byte[] input = new byte[10]; + int read = await context.Request.Body.ReadAsync(input, 0, input.Length, context.DisconnectToken); + Assert.False(context.DisconnectToken.IsCancellationRequested); + // The client should timeout and disconnect, making this read fail. + var assertTask = Assert.ThrowsAsync(async () => await context.Request.Body.ReadAsync(input, 0, input.Length, context.DisconnectToken)); + client.CancelPendingRequests(); + await assertTask; + content.Block.Release(); + context.Dispose(); + + await Assert.ThrowsAsync(async () => await responseTask); + } + } + private Task SendRequestAsync(string uri, string upload) { return SendRequestAsync(uri, new StringContent(upload)); @@ -177,6 +327,7 @@ namespace Microsoft.Net.Http.Server { using (HttpClient client = new HttpClient()) { + client.Timeout = TimeSpan.FromSeconds(10); HttpResponseMessage response = await client.PostAsync(uri, content); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index bd9ab9bf0f..0a9a476ff7 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -185,6 +185,94 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task ResponseBody_WriteAsyncWithActiveCancellationToken_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + var cts = new CancellationTokenSource(); + // First write sends headers + await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_WriteAsyncWithTimerCancellationToken_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(1)); + // First write sends headers + await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_FirstWriteAsyncWithCancelledCancellationToken_CancelsButDoesNotAbort() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + var cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_SecondWriteAsyncWithCancelledCancellationToken_CancelsButDoesNotAbort() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + var cts = new CancellationTokenSource(); + // First write sends headers + await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + cts.Cancel(); + var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) From 4b76d93801ba277fcd5a440790ef6d29b7703a06 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 25 Aug 2014 14:18:18 -0700 Subject: [PATCH 101/597] Change spelling of Cancelled to Canceled. Cleanup. --- .../Constants.cs | 1 - src/Microsoft.Net.Http.Server/Constants.cs | 43 ------------------- src/Microsoft.Net.Http.Server/Helpers.cs | 2 +- .../RequestProcessing/RequestContext.cs | 2 +- .../RequestProcessing/RequestStream.cs | 2 +- .../RequestProcessing/ResponseStream.cs | 10 ++--- .../WebSocketHttpListenerDuplexStream.cs | 2 +- .../RequestTests.cs | 3 -- .../ServerTests.cs | 4 +- .../RequestBodyTests.cs | 2 +- .../ResponseBodyTests.cs | 4 +- .../ServerTests.cs | 4 +- 12 files changed, 16 insertions(+), 63 deletions(-) diff --git a/src/Microsoft.AspNet.Security.Windows/Constants.cs b/src/Microsoft.AspNet.Security.Windows/Constants.cs index 733190a708..f5f618cd83 100644 --- a/src/Microsoft.AspNet.Security.Windows/Constants.cs +++ b/src/Microsoft.AspNet.Security.Windows/Constants.cs @@ -27,7 +27,6 @@ namespace Microsoft.AspNet.Security.Windows { internal const string VersionKey = "owin.Version"; internal const string OwinVersion = "1.0"; - internal const string CallCancelledKey = "owin.CallCancelled"; internal const string RequestBodyKey = "owin.RequestBody"; internal const string RequestHeadersKey = "owin.RequestHeaders"; diff --git a/src/Microsoft.Net.Http.Server/Constants.cs b/src/Microsoft.Net.Http.Server/Constants.cs index 2d8ae594ab..e3336f6bea 100644 --- a/src/Microsoft.Net.Http.Server/Constants.cs +++ b/src/Microsoft.Net.Http.Server/Constants.cs @@ -27,49 +27,6 @@ namespace Microsoft.Net.Http.Server { internal static class Constants { - internal const string VersionKey = "owin.Version"; - internal const string OwinVersion = "1.0"; - internal const string CallCancelledKey = "owin.CallCancelled"; - - internal const string ServerCapabilitiesKey = "server.Capabilities"; - - internal const string RequestBodyKey = "owin.RequestBody"; - internal const string RequestHeadersKey = "owin.RequestHeaders"; - internal const string RequestSchemeKey = "owin.RequestScheme"; - internal const string RequestMethodKey = "owin.RequestMethod"; - internal const string RequestPathBaseKey = "owin.RequestPathBase"; - internal const string RequestPathKey = "owin.RequestPath"; - internal const string RequestQueryStringKey = "owin.RequestQueryString"; - internal const string HttpRequestProtocolKey = "owin.RequestProtocol"; - - internal const string HttpResponseProtocolKey = "owin.ResponseProtocol"; - internal const string ResponseStatusCodeKey = "owin.ResponseStatusCode"; - internal const string ResponseReasonPhraseKey = "owin.ResponseReasonPhrase"; - internal const string ResponseHeadersKey = "owin.ResponseHeaders"; - internal const string ResponseBodyKey = "owin.ResponseBody"; - - internal const string ClientCertifiateKey = "ssl.ClientCertificate"; - - internal const string RemoteIpAddressKey = "server.RemoteIpAddress"; - internal const string RemotePortKey = "server.RemotePort"; - internal const string LocalIpAddressKey = "server.LocalIpAddress"; - internal const string LocalPortKey = "server.LocalPort"; - internal const string IsLocalKey = "server.IsLocal"; - internal const string ServerOnSendingHeadersKey = "server.OnSendingHeaders"; - internal const string ServerLoggerFactoryKey = "server.LoggerFactory"; - - internal const string OpaqueVersionKey = "opaque.Version"; - internal const string OpaqueVersion = "1.0"; - internal const string OpaqueFuncKey = "opaque.Upgrade"; - internal const string OpaqueStreamKey = "opaque.Stream"; - internal const string OpaqueCallCancelledKey = "opaque.CallCancelled"; - - internal const string SendFileVersionKey = "sendfile.Version"; - internal const string SendFileVersion = "1.0"; - internal const string SendFileSupportKey = "sendfile.Support"; - internal const string SendFileConcurrencyKey = "sendfile.Concurrency"; - internal const string Overlapped = "Overlapped"; - internal const string HttpScheme = "http"; internal const string HttpsScheme = "https"; internal const string SchemeDelimiter = "://"; diff --git a/src/Microsoft.Net.Http.Server/Helpers.cs b/src/Microsoft.Net.Http.Server/Helpers.cs index a8e0a2e5a9..0d89af2dde 100644 --- a/src/Microsoft.Net.Http.Server/Helpers.cs +++ b/src/Microsoft.Net.Http.Server/Helpers.cs @@ -33,7 +33,7 @@ namespace Microsoft.Net.Http.Server return Task.FromResult(null); } - internal static Task CancelledTask() + internal static Task CanceledTask() { TaskCompletionSource tcs = new TaskCompletionSource(); tcs.TrySetCanceled(); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 0c3ea2baf4..337959c064 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -37,7 +37,7 @@ namespace Microsoft.Net.Http.Server { public sealed class RequestContext : IDisposable { - internal static Action AbortDelegate = Abort; + internal static readonly Action AbortDelegate = Abort; private WebListener _server; private Request _request; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index aed48a5383..0be3ff8a78 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -321,7 +321,7 @@ namespace Microsoft.Net.Http.Server if (cancellationToken.IsCancellationRequested) { - return Helpers.CancelledTask(); + return Helpers.CanceledTask(); } // TODO: Verbose log parameters diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index ce086c4ca0..7bdf20953c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -137,7 +137,7 @@ namespace Microsoft.Net.Http.Server if (cancellationToken.IsCancellationRequested) { - return Helpers.CancelledTask(); + return Helpers.CanceledTask(); } CancellationTokenRegistration cancellationRegistration; @@ -531,7 +531,7 @@ namespace Microsoft.Net.Http.Server if (cancellationToken.IsCancellationRequested) { - return Helpers.CancelledTask(); + return Helpers.CanceledTask(); } CancellationTokenRegistration cancellationRegistration; @@ -639,7 +639,7 @@ namespace Microsoft.Net.Http.Server if (cancellationToken.IsCancellationRequested) { - return Helpers.CancelledTask(); + return Helpers.CanceledTask(); } CancellationTokenRegistration cancellationRegistration; @@ -853,8 +853,8 @@ namespace Microsoft.Net.Http.Server _leftToWrite = long.MaxValue; } - // The final Content-Length async write can only be cancelled by CancelIoEx. - // Sync can only be cancelled by CancelSynchronousIo, but we don't attempt this right now. + // The final Content-Length async write can only be Canceled by CancelIoEx. + // Sync can only be Canceled by CancelSynchronousIo, but we don't attempt this right now. [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = "It is safe to ignore the return value on a cancel operation because the connection is being closed")] internal unsafe void CancelLastWrite(SafeHandle requestQueueHandle) diff --git a/src/Microsoft.Net.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs b/src/Microsoft.Net.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs index f5c77b4eb4..1e23d2ec6e 100644 --- a/src/Microsoft.Net.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs +++ b/src/Microsoft.Net.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs @@ -667,7 +667,7 @@ namespace Microsoft.AspNet.WebSockets throw; } - // throw OperationCancelledException when canceled by the caller + // throw OperationCanceledException when canceled by the caller // otherwise swallow the exception cancellationToken.ThrowIfCancellationRequested(); } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 8a4efdc974..1dce566c7b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -41,9 +41,6 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - // General keys - // TODO: Assert.True(env.Get("owin.CallCancelled").CanBeCanceled); - var requestInfo = httpContext.GetFeature(); // Request Keys diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 337b2359d4..7e39695da9 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -190,7 +190,7 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task Server_ClientDisconnects_CallCancelled() + public async Task Server_ClientDisconnects_CallCanceled() { TimeSpan interval = TimeSpan.FromSeconds(1); ManualResetEvent received = new ManualResetEvent(false); @@ -225,7 +225,7 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task Server_Abort_CallCancelled() + public async Task Server_Abort_CallCanceled() { TimeSpan interval = TimeSpan.FromSeconds(100); ManualResetEvent received = new ManualResetEvent(false); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index 47dfbcb117..de847e9331 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -169,7 +169,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task RequestBody_ReadAsyncAlreadyCancelled_ReturnsCanceledTask() + public async Task RequestBody_ReadAsyncAlreadyCanceled_ReturnsCanceledTask() { string address; using (var server = Utilities.CreateHttpServer(out address)) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 0a9a476ff7..b76bda6db0 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -229,7 +229,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseBody_FirstWriteAsyncWithCancelledCancellationToken_CancelsButDoesNotAbort() + public async Task ResponseBody_FirstWriteAsyncWithCanceledCancellationToken_CancelsButDoesNotAbort() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -251,7 +251,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseBody_SecondWriteAsyncWithCancelledCancellationToken_CancelsButDoesNotAbort() + public async Task ResponseBody_SecondWriteAsyncWithCanceledCancellationToken_CancelsButDoesNotAbort() { string address; using (var server = Utilities.CreateHttpServer(out address)) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 50b325c003..23c641dea3 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -73,7 +73,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task Server_ClientDisconnects_CallCancelled() + public async Task Server_ClientDisconnects_CallCanceled() { TimeSpan interval = TimeSpan.FromSeconds(1); ManualResetEvent canceled = new ManualResetEvent(false); @@ -103,7 +103,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task Server_Abort_CallCancelled() + public async Task Server_Abort_CallCanceled() { TimeSpan interval = TimeSpan.FromSeconds(1); ManualResetEvent canceled = new ManualResetEvent(false); From 8cda77db5a80975142199233a6bfa41eab4a3d45 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 27 Aug 2014 16:09:59 -0700 Subject: [PATCH 102/597] #25 - Fix request stream async memory leak, dispose RequestStreamAsyncResult. --- .../RequestProcessing/RequestStream.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 0be3ff8a78..8ed8cbb2f2 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -566,6 +566,7 @@ namespace Microsoft.Net.Http.Server } } } + Dispose(); } internal void Fail(Exception ex) @@ -582,6 +583,7 @@ namespace Microsoft.Net.Http.Server // TODO: Log } } + Dispose(); } [SuppressMessage("Microsoft.Usage", "CA2216:DisposableTypesShouldDeclareFinalizer", Justification = "The disposable resource referenced does have a finalizer.")] From e5543d6adf23c98f9a98c4026e3eac1a008da0e0 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 28 Aug 2014 09:04:46 -0700 Subject: [PATCH 103/597] Move RequestStreamAsyncResult to its own file. --- .../RequestProcessing/RequestStream.cs | 181 +-------------- .../RequestStreamAsyncResult.cs | 209 ++++++++++++++++++ 2 files changed, 210 insertions(+), 180 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 8ed8cbb2f2..cd14f84ca4 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -22,7 +22,6 @@ // ------------------------------------------------------------------------------ using System; -using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.InteropServices; using System.Threading; @@ -184,7 +183,7 @@ namespace Microsoft.Net.Http.Server return (int)dataRead; } - private void UpdateAfterRead(uint statusCode, uint dataRead) + internal void UpdateAfterRead(uint statusCode, uint dataRead) { if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF || dataRead == 0) { @@ -446,183 +445,5 @@ namespace Microsoft.Net.Http.Server base.Dispose(disposing); } } - - private unsafe class RequestStreamAsyncResult : IAsyncResult, IDisposable - { - private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(Callback); - - private SafeNativeOverlapped _overlapped; - private IntPtr _pinnedBuffer; - private uint _dataAlreadyRead = 0; - private TaskCompletionSource _tcs; - private RequestStream _requestStream; - private AsyncCallback _callback; - private CancellationTokenRegistration _cancellationRegistration; - - internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback) - { - _requestStream = requestStream; - _tcs = new TaskCompletionSource(userState); - _callback = callback; - } - - internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, uint dataAlreadyRead) - : this(requestStream, userState, callback) - { - _dataAlreadyRead = dataAlreadyRead; - } - - internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead) - : this(requestStream, userState, callback, buffer, offset, dataAlreadyRead, new CancellationTokenRegistration()) - { - } - - internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead, CancellationTokenRegistration cancellationRegistration) - : this(requestStream, userState, callback) - { - _dataAlreadyRead = dataAlreadyRead; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, buffer)); - _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); - _cancellationRegistration = cancellationRegistration; - } - - internal RequestStream RequestStream - { - get { return _requestStream; } - } - - internal SafeNativeOverlapped NativeOverlapped - { - get { return _overlapped; } - } - - internal IntPtr PinnedBuffer - { - get { return _pinnedBuffer; } - } - - internal uint DataAlreadyRead - { - get { return _dataAlreadyRead; } - } - - internal Task Task - { - get { return _tcs.Task; } - } - - internal bool EndCalled { get; set; } - - internal void IOCompleted(uint errorCode, uint numBytes) - { - IOCompleted(this, errorCode, numBytes); - } - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting to callback")] - private static void IOCompleted(RequestStreamAsyncResult asyncResult, uint errorCode, uint numBytes) - { - try - { - if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) - { - asyncResult.Fail(new WebListenerException((int)errorCode)); - } - else - { - // TODO: Verbose log dump data read - asyncResult.Complete((int)numBytes, errorCode); - } - } - catch (Exception e) - { - asyncResult.Fail(e); - } - } - - private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) - { - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - RequestStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as RequestStreamAsyncResult; - - IOCompleted(asyncResult, errorCode, numBytes); - } - - internal void Complete(int read, uint errorCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - if (_tcs.TrySetResult(read + (int)DataAlreadyRead)) - { - RequestStream.UpdateAfterRead((uint)errorCode, (uint)(read + DataAlreadyRead)); - if (_callback != null) - { - try - { - _callback(this); - } - catch (Exception) - { - // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. - } - } - } - Dispose(); - } - - internal void Fail(Exception ex) - { - if (_tcs.TrySetException(ex) && _callback != null) - { - try - { - _callback(this); - } - catch (Exception) - { - // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. - // TODO: Log - } - } - Dispose(); - } - - [SuppressMessage("Microsoft.Usage", "CA2216:DisposableTypesShouldDeclareFinalizer", Justification = "The disposable resource referenced does have a finalizer.")] - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (_overlapped != null) - { - _overlapped.Dispose(); - } - _cancellationRegistration.Dispose(); - } - } - - public object AsyncState - { - get { return _tcs.Task.AsyncState; } - } - - public WaitHandle AsyncWaitHandle - { - get { return ((IAsyncResult)_tcs.Task).AsyncWaitHandle; } - } - - public bool CompletedSynchronously - { - get { return ((IAsyncResult)_tcs.Task).CompletedSynchronously; } - } - - public bool IsCompleted - { - get { return _tcs.Task.IsCompleted; } - } - } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs new file mode 100644 index 0000000000..effc75c6f7 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs @@ -0,0 +1,209 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Net.Http.Server +{ + internal unsafe class RequestStreamAsyncResult : IAsyncResult, IDisposable + { + private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(Callback); + + private SafeNativeOverlapped _overlapped; + private IntPtr _pinnedBuffer; + private uint _dataAlreadyRead; + private TaskCompletionSource _tcs; + private RequestStream _requestStream; + private AsyncCallback _callback; + private CancellationTokenRegistration _cancellationRegistration; + + internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback) + { + _requestStream = requestStream; + _tcs = new TaskCompletionSource(userState); + _callback = callback; + } + + internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, uint dataAlreadyRead) + : this(requestStream, userState, callback) + { + _dataAlreadyRead = dataAlreadyRead; + } + + internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead) + : this(requestStream, userState, callback, buffer, offset, dataAlreadyRead, new CancellationTokenRegistration()) + { + } + + internal RequestStreamAsyncResult(RequestStream requestStream, object userState, AsyncCallback callback, byte[] buffer, int offset, uint dataAlreadyRead, CancellationTokenRegistration cancellationRegistration) + : this(requestStream, userState, callback) + { + _dataAlreadyRead = dataAlreadyRead; + Overlapped overlapped = new Overlapped(); + overlapped.AsyncResult = this; + _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, buffer)); + _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); + _cancellationRegistration = cancellationRegistration; + } + + internal RequestStream RequestStream + { + get { return _requestStream; } + } + + internal SafeNativeOverlapped NativeOverlapped + { + get { return _overlapped; } + } + + internal IntPtr PinnedBuffer + { + get { return _pinnedBuffer; } + } + + internal uint DataAlreadyRead + { + get { return _dataAlreadyRead; } + } + + internal Task Task + { + get { return _tcs.Task; } + } + + internal bool EndCalled { get; set; } + + internal void IOCompleted(uint errorCode, uint numBytes) + { + IOCompleted(this, errorCode, numBytes); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting to callback")] + private static void IOCompleted(RequestStreamAsyncResult asyncResult, uint errorCode, uint numBytes) + { + try + { + if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + { + asyncResult.Fail(new WebListenerException((int)errorCode)); + } + else + { + // TODO: Verbose log dump data read + asyncResult.Complete((int)numBytes, errorCode); + } + } + catch (Exception e) + { + asyncResult.Fail(e); + } + } + + private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) + { + Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); + RequestStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as RequestStreamAsyncResult; + + IOCompleted(asyncResult, errorCode, numBytes); + } + + internal void Complete(int read, uint errorCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + if (_tcs.TrySetResult(read + (int)DataAlreadyRead)) + { + RequestStream.UpdateAfterRead((uint)errorCode, (uint)(read + DataAlreadyRead)); + if (_callback != null) + { + try + { + _callback(this); + } + catch (Exception) + { + // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. + } + } + } + Dispose(); + } + + internal void Fail(Exception ex) + { + if (_tcs.TrySetException(ex) && _callback != null) + { + try + { + _callback(this); + } + catch (Exception) + { + // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. + // TODO: Log + } + } + Dispose(); + } + + [SuppressMessage("Microsoft.Usage", "CA2216:DisposableTypesShouldDeclareFinalizer", Justification = "The disposable resource referenced does have a finalizer.")] + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_overlapped != null) + { + _overlapped.Dispose(); + } + _cancellationRegistration.Dispose(); + } + } + + public object AsyncState + { + get { return _tcs.Task.AsyncState; } + } + + public WaitHandle AsyncWaitHandle + { + get { return ((IAsyncResult)_tcs.Task).AsyncWaitHandle; } + } + + public bool CompletedSynchronously + { + get { return ((IAsyncResult)_tcs.Task).CompletedSynchronously; } + } + + public bool IsCompleted + { + get { return _tcs.Task.IsCompleted; } + } + } +} \ No newline at end of file From a7e97313b53b0613ceb98cfb2106fff94af89a59 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 29 Aug 2014 00:07:19 -0700 Subject: [PATCH 104/597] Updated to use the new target framework in project.json --- samples/HelloWorld/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNet.Security.Windows/project.json | 2 +- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- src/Microsoft.Net.WebSockets/project.json | 2 +- test/Microsoft.AspNet.Security.Windows.Test/project.json | 2 +- .../project.json | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 3a1514068e..dce1c90459 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -4,7 +4,7 @@ }, "frameworks": { "net45": { }, - "k10" : { + "aspnetcore50" : { "dependencies": { "System.Collections": "4.0.10.0", "System.Console" : "4.0.0.0", diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index bd23b22505..972bf20843 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -9,7 +9,7 @@ "frameworks": { "net45": { }, - "k10": { + "aspnetcore50": { "dependencies": { "System.Collections": "4.0.10.0", "System.Console": "4.0.0.0", diff --git a/src/Microsoft.AspNet.Security.Windows/project.json b/src/Microsoft.AspNet.Security.Windows/project.json index d2e616766c..566ae29eff 100644 --- a/src/Microsoft.AspNet.Security.Windows/project.json +++ b/src/Microsoft.AspNet.Security.Windows/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "dependencies": { }, diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 50b13d703d..dd5b4c4380 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -14,7 +14,7 @@ }, "frameworks": { "net45": {}, - "k10": { + "aspnetcore50": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.10.0", diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index a6ffbe5438..2a7c15f92b 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -9,7 +9,7 @@ }, "frameworks": { "net45": {}, - "k10": { + "aspnetcore50": { "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", "Microsoft.Win32.Primitives": "4.0.0.0", diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 0a52489089..7fd3a3907e 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -6,7 +6,7 @@ "compilationOptions" : { "allowUnsafe": true }, "frameworks": { "net45" : { }, - "k10" : { + "aspnetcore50" : { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", "System.Collections": "4.0.10.0", diff --git a/test/Microsoft.AspNet.Security.Windows.Test/project.json b/test/Microsoft.AspNet.Security.Windows.Test/project.json index 841fe8d67c..37e979b7da 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/project.json +++ b/test/Microsoft.AspNet.Security.Windows.Test/project.json @@ -1,4 +1,4 @@ -{ +{ "dependencies": { "Microsoft.AspNet.Security.Windows" : "", "Microsoft.AspNet.Server.WebListener" : "", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index cd4dec25c2..e9c9096e41 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,4 +1,4 @@ -{ +{ "commands": { "test": "Xunit.KRunner" }, diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 31d057271a..fa9c4b849a 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,4 +1,4 @@ -{ +{ "commands": { "test": "Xunit.KRunner" }, From a1c2f68a58ce621059eefd9f2351a06d8252e0dc Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 4 Sep 2014 01:44:15 -0700 Subject: [PATCH 105/597] Updated to use the new target framework in project.json --- samples/HelloWorld/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNet.Security.Windows/project.json | 2 +- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/AuthenticationManager.cs | 6 +++--- src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs | 2 +- .../NativeInterop/HttpSysSettings.cs | 6 +++--- .../NativeInterop/NclUtilities.cs | 2 +- .../RequestProcessing/OpaqueStream.cs | 4 ++-- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestStream.cs | 8 ++++---- .../RequestProcessing/RequestUriBuilder.cs | 6 +++--- .../RequestProcessing/Response.cs | 2 +- .../RequestProcessing/ResponseStream.cs | 6 +++--- .../RequestProcessing/ResponseStreamAsyncResult.cs | 2 +- src/Microsoft.Net.Http.Server/TimeoutManager.cs | 2 +- src/Microsoft.Net.Http.Server/WebListener.cs | 8 ++++---- src/Microsoft.Net.Http.Server/WebListenerException.cs | 2 +- .../SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs | 2 +- .../SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs | 4 ++-- .../fx/System/Diagnostics/TraceEventType.cs | 4 ++-- src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs | 4 ++-- .../System/Runtime/InteropServices/ExternalException.cs | 4 ++-- .../fx/System/SafeNativeMethods.cs | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- .../NativeInterop/SafeNativeOverlapped.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 2 +- src/Microsoft.Net.WebSockets/WebSocketBase.cs | 6 +++--- src/Microsoft.Net.WebSockets/WebSocketBuffer.cs | 4 ++-- src/Microsoft.Net.WebSockets/WebSocketException.cs | 2 +- .../SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs | 4 ++-- .../fx/System/AccessViolationException.cs | 4 ++-- .../fx/System/ComponentModel/Win32Exception.cs | 4 ++-- src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs | 4 ++-- .../System/Runtime/InteropServices/ExternalException.cs | 4 ++-- .../fx/System/SafeNativeMethods.cs | 2 +- src/Microsoft.Net.WebSockets/fx/System/SystemException.cs | 4 ++-- src/Microsoft.Net.WebSockets/project.json | 2 +- test/Microsoft.AspNet.Security.Windows.Test/project.json | 2 +- .../RequestBodyTests.cs | 2 +- .../project.json | 2 +- .../RequestBodyTests.cs | 6 +++--- .../project.json | 2 +- 43 files changed, 73 insertions(+), 73 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index dce1c90459..4f4c0e622f 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,7 +3,7 @@ "Microsoft.Net.Http.Server" : "" }, "frameworks": { - "net45": { }, + "aspnet50": { }, "aspnetcore50" : { "dependencies": { "System.Collections": "4.0.10.0", diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 972bf20843..4ae5346393 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -7,7 +7,7 @@ }, "commands": { "web": "Microsoft.AspNet.Hosting --server=Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:8080" }, "frameworks": { - "net45": { + "aspnet50": { }, "aspnetcore50": { "dependencies": { diff --git a/src/Microsoft.AspNet.Security.Windows/project.json b/src/Microsoft.AspNet.Security.Windows/project.json index 566ae29eff..710de00f3a 100644 --- a/src/Microsoft.AspNet.Security.Windows/project.json +++ b/src/Microsoft.AspNet.Security.Windows/project.json @@ -5,7 +5,7 @@ "compilationOptions" : { "allowUnsafe": true }, "frameworks": { - "net45" : { + "aspnet50" : { "dependencies": { } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index dd5b4c4380..2951f53f89 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -13,7 +13,7 @@ "allowUnsafe": true }, "frameworks": { - "net45": {}, + "aspnet50": {}, "aspnetcore50": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 4d88e5716a..4dd506ba29 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -39,7 +39,7 @@ namespace Microsoft.Net.Http.Server /// public sealed class AuthenticationManager { -#if NET45 +#if ASPNET50 private static readonly int AuthInfoSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO)); #else @@ -163,7 +163,7 @@ namespace Microsoft.Net.Http.Server && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { -#if NET45 +#if ASPNET50 return true; #endif } @@ -176,7 +176,7 @@ namespace Microsoft.Net.Http.Server && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { -#if NET45 +#if ASPNET50 return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken, GetAuthTypeFromRequest(requestInfo->pInfo->AuthType).ToString())); #endif diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index 5d78b9a498..ff8c54aa99 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server static ComNetOS() { -#if NET45 +#if ASPNET50 var win8Version = new Version(6, 2); IsWin8orLater = (Environment.OSVersion.Version >= win8Version); #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs index 94d60a3abb..f55d833576 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Security; -#if NET45 +#if ASPNET50 using Microsoft.Win32; #endif @@ -34,7 +34,7 @@ namespace Microsoft.Net.Http.Server { internal static class HttpSysSettings { -#if NET45 +#if ASPNET50 private const string HttpSysParametersKey = @"System\CurrentControlSet\Services\HTTP\Parameters"; #endif private const bool EnableNonUtf8Default = true; @@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server } private static void ReadHttpSysRegistrySettings() -#if !NET45 +#if !ASPNET50 { } #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs index e5934498d9..c3aaec9cb7 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server get { return Environment.HasShutdownStarted -#if NET45 +#if ASPNET50 || AppDomain.CurrentDomain.IsFinalizingForUnload() #endif ; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs index 8c66cbca9a..54215adb62 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs @@ -109,7 +109,7 @@ namespace Microsoft.Net.Http.Server { return _requestStream.ReadByte(); } -#if NET45 +#if ASPNET50 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _requestStream.BeginRead(buffer, offset, count, callback, state); @@ -143,7 +143,7 @@ namespace Microsoft.Net.Http.Server { _responseStream.WriteByte(value); } -#if NET45 +#if ASPNET50 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _responseStream.BeginWrite(buffer, offset, count, callback, state); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index daf92329ed..3d03cbc366 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -29,7 +29,7 @@ using System.Net; using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; -#if NET45 +#if ASPNET50 using System.Security.Principal; #endif using System.Threading; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index cd14f84ca4..46aa6db146 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -191,7 +191,7 @@ namespace Microsoft.Net.Http.Server } } -#if NET45 +#if ASPNET50 public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -283,7 +283,7 @@ namespace Microsoft.Net.Http.Server return asyncResult; } -#if NET45 +#if ASPNET50 public override int EndRead(IAsyncResult asyncResult) #else public int EndRead(IAsyncResult asyncResult) @@ -416,7 +416,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if NET45 +#if ASPNET50 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -425,7 +425,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if NET45 +#if ASPNET50 public override void EndWrite(IAsyncResult asyncResult) #else public void EndWrite(IAsyncResult asyncResult) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 6fd6467468..0da68b19bc 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -57,8 +57,8 @@ namespace Microsoft.Net.Http.Server // // When parsing ANSI (Latin 1) encoded path '/pa%C4th/', %C4 will be added to rawOctets and when // we reach 't', the content of rawOctets { 0xC4 } will be fed into the ANSI encoding. The resulting - // string '�' will be percent encoded into UTF-8 octets and appended to requestUriString. The final - // path will be '/pa%C3%84th/', where '%C3%84' is the UTF-8 percent encoded character '�'. + // string '�' will be percent encoded into UTF-8 octets and appended to requestUriString. The final + // path will be '/pa%C3%84th/', where '%C3%84' is the UTF-8 percent encoded character '�'. private List _rawOctets; private string _rawPath; @@ -70,7 +70,7 @@ namespace Microsoft.Net.Http.Server // TODO: False triggers more detailed/correct parsing, but it's rather slow. UseCookedRequestUrl = true; // SettingsSectionInternal.Section.HttpListenerUnescapeRequestUrl; Utf8Encoding = new UTF8Encoding(false, true); -#if NET45 +#if ASPNET50 AnsiEncoding = Encoding.GetEncoding(0, new EncoderExceptionFallback(), new DecoderExceptionFallback()); #else AnsiEncoding = Utf8Encoding; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 95193ca2bb..28ea172d40 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -701,7 +701,7 @@ namespace Microsoft.Net.Http.Server knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = -#if NET45 +#if ASPNET50 (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); #else (uint)Marshal.SizeOf(); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 7bdf20953c..3a5b85699d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -197,7 +197,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } -#if NET45 +#if ASPNET50 public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); @@ -357,7 +357,7 @@ namespace Microsoft.Net.Http.Server // TODO: Verbose log data written } -#if NET45 +#if ASPNET50 public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -464,7 +464,7 @@ namespace Microsoft.Net.Http.Server return asyncResult; } -#if NET45 +#if ASPNET50 public override void EndWrite(IAsyncResult asyncResult) #else public void EndWrite(IAsyncResult asyncResult) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 6c829cddba..1a14b15485 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -140,7 +140,7 @@ namespace Microsoft.Net.Http.Server overlapped.AsyncResult = this; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. -#if NET45 +#if ASPNET50 // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive. diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index e7bd3b2236..53f819d99b 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -35,7 +35,7 @@ namespace Microsoft.Net.Http.Server /// public sealed class TimeoutManager { -#if NET45 +#if ASPNET50 private static readonly int TimeoutLimitSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO)); #else diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index d8d80772dc..d68eceb01d 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -44,7 +44,7 @@ namespace Microsoft.Net.Http.Server public sealed class WebListener : IDisposable { private const long DefaultRequestQueueLength = 1000; // Http.sys default. -#if NET45 +#if ASPNET50 private static readonly Type ChannelBindingStatusType = typeof(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS); private static readonly int RequestChannelBindStatusSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS)); @@ -818,7 +818,7 @@ namespace Microsoft.Net.Http.Server knownHeaderInfo[httpResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[httpResponse.ResponseInfoCount].Length = -#if NET45 +#if ASPNET50 (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); #else (uint)Marshal.SizeOf(); @@ -910,7 +910,7 @@ namespace Microsoft.Net.Http.Server private static int GetTokenOffsetFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); -#if NET45 +#if ASPNET50 IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelToken")); #else IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); @@ -922,7 +922,7 @@ namespace Microsoft.Net.Http.Server private static int GetTokenSizeFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); -#if NET45 +#if ASPNET50 return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelTokenSize")); #else return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); diff --git a/src/Microsoft.Net.Http.Server/WebListenerException.cs b/src/Microsoft.Net.Http.Server/WebListenerException.cs index a47346c509..e411eccbff 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerException.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerException.cs @@ -45,7 +45,7 @@ namespace Microsoft.Net.Http.Server : base(errorCode, message) { } -#if NET45 +#if ASPNET50 // the base class returns the HResult with this property // we need the Win32 Error Code, hence the override. public override int ErrorCode diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs index 421412244e..c32fe193c6 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if !NET45 +#if !ASPNET50 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 9e1e783200..93ae53059d 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if !NET45 +#if !ASPNET50 namespace Microsoft.Win32.SafeHandles { @@ -45,4 +45,4 @@ namespace Microsoft.Win32.SafeHandles } } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs index ce9c830d9e..27c11162bb 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !NET45 +#if !ASPNET50 using System; using System.ComponentModel; @@ -49,4 +49,4 @@ namespace System.Diagnostics } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs index cc20e7969c..693cecaf1d 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !NET45 +#if !ASPNET50 namespace System { @@ -30,4 +30,4 @@ namespace System public const string Kernel32 = "kernel32.dll"; } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs index eae4f7dae2..7ddb66a918 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if !NET45 +#if !ASPNET50 namespace System.Runtime.InteropServices { @@ -112,4 +112,4 @@ namespace System.Runtime.InteropServices } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs index ae88c8bda9..098a797cdd 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !NET45 +#if !ASPNET50 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 2a7c15f92b..cb314b1c30 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -8,7 +8,7 @@ "allowUnsafe": true }, "frameworks": { - "net45": {}, + "aspnet50": {}, "aspnetcore50": { "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs index 2bbf1c58bf..02de75baaa 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs @@ -87,7 +87,7 @@ namespace Microsoft.Net.WebSockets get { return Environment.HasShutdownStarted -#if NET45 +#if ASPNET50 || AppDomain.CurrentDomain.IsFinalizingForUnload() #endif ; diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs index c2002b7f22..de2d07588f 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -161,7 +161,7 @@ namespace Microsoft.Net.WebSockets static WebSocketProtocolComponent() { -#if NET45 +#if ASPNET50 DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); #else DllFileName = Path.Combine(Environment.GetEnvironmentVariable("SYSTEMROOT"), "System32", WEBSOCKET); diff --git a/src/Microsoft.Net.WebSockets/WebSocketBase.cs b/src/Microsoft.Net.WebSockets/WebSocketBase.cs index 30c9ebc9d5..d845cc1625 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBase.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBase.cs @@ -1103,7 +1103,7 @@ namespace Microsoft.Net.WebSockets if (thisLockTaken || sessionHandleLockTaken) { -#if NET45 +#if ASPNET50 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -1189,7 +1189,7 @@ namespace Microsoft.Net.WebSockets Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); if (lockTaken) { -#if NET45 +#if ASPNET50 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -2253,7 +2253,7 @@ namespace Microsoft.Net.WebSockets "'webSocket.m_KeepAliveTracker' MUST NOT be NULL at this point."); int keepAliveIntervalMilliseconds = (int)_keepAliveInterval.TotalMilliseconds; Contract.Assert(keepAliveIntervalMilliseconds > 0, "'keepAliveIntervalMilliseconds' MUST be POSITIVE."); -#if NET45 +#if ASPNET50 if (ExecutionContext.IsFlowSuppressed()) { _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); diff --git a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs index a34b458f7c..7378812572 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs @@ -50,7 +50,7 @@ namespace Microsoft.Net.WebSockets public const int MinSendBufferSize = 16; internal const int MinReceiveBufferSize = 256; internal const int MaxBufferSize = 64 * 1024; -#if NET45 +#if ASPNET50 private static readonly int SizeOfUInt = Marshal.SizeOf(typeof(uint)); private static readonly int SizeOfBool = Marshal.SizeOf(typeof(bool)); #else @@ -713,4 +713,4 @@ namespace Microsoft.Net.WebSockets public const int SendPayloadSpecified = 1; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.Net.WebSockets/WebSocketException.cs b/src/Microsoft.Net.WebSockets/WebSocketException.cs index 1e923616ad..74ee1663e8 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketException.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketException.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; namespace Microsoft.Net.WebSockets { -#if NET45 +#if ASPNET50 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] #endif internal sealed class WebSocketException : Win32Exception diff --git a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 9e1e783200..93ae53059d 100644 --- a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if !NET45 +#if !ASPNET50 namespace Microsoft.Win32.SafeHandles { @@ -45,4 +45,4 @@ namespace Microsoft.Win32.SafeHandles } } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs index f7aa7f941f..7c0f5bf195 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if !NET45 +#if !ASPNET50 using System; using System.Collections.Generic; @@ -30,4 +30,4 @@ namespace System } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs index ce75afbf7e..bdd0fa07bd 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !NET45 +#if !ASPNET50 using System.Runtime.InteropServices; using System.Text; @@ -126,4 +126,4 @@ namespace System.ComponentModel } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs index cc20e7969c..693cecaf1d 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !NET45 +#if !ASPNET50 namespace System { @@ -30,4 +30,4 @@ namespace System public const string Kernel32 = "kernel32.dll"; } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs index eae4f7dae2..7ddb66a918 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if !NET45 +#if !ASPNET50 namespace System.Runtime.InteropServices { @@ -112,4 +112,4 @@ namespace System.Runtime.InteropServices } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs index ae88c8bda9..098a797cdd 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !NET45 +#if !ASPNET50 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs index b6d2d3e3f3..3ab212bca4 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if !NET45 +#if !ASPNET50 using System; using System.Collections.Generic; @@ -30,4 +30,4 @@ namespace System } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 7fd3a3907e..b61f880017 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -5,7 +5,7 @@ }, "compilationOptions" : { "allowUnsafe": true }, "frameworks": { - "net45" : { }, + "aspnet50" : { }, "aspnetcore50" : { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", diff --git a/test/Microsoft.AspNet.Security.Windows.Test/project.json b/test/Microsoft.AspNet.Security.Windows.Test/project.json index 37e979b7da..f4e5ecfa6f 100644 --- a/test/Microsoft.AspNet.Security.Windows.Test/project.json +++ b/test/Microsoft.AspNet.Security.Windows.Test/project.json @@ -8,7 +8,7 @@ "xunit.execution": "2.0.0-aspnet-*" }, "frameworks": { - "net45": { + "aspnet50": { "dependencies": { "System.Net.Http": "", "System.Net.Http.WebRequest": "" diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 8a92ce2a04..f630a6a85f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal("Hello World", response); } } -#if NET45 +#if ASPNET50 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index e9c9096e41..edff879192 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -15,7 +15,7 @@ "Xunit.KRunner": "1.0.0-*" }, "frameworks": { - "net45": { + "aspnet50": { "dependencies": { "System.Net.Http": "", "System.Net.Http.WebRequest": "", diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index de847e9331..d7ca42c3c9 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.IO; @@ -51,7 +51,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal("Hello World", response); } } -#if NET45 +#if ASPNET50 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { @@ -402,4 +402,4 @@ namespace Microsoft.Net.Http.Server } } } -} \ No newline at end of file +} diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index fa9c4b849a..0c0784e8e7 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -7,7 +7,7 @@ "Xunit.KRunner": "1.0.0-*" }, "frameworks": { - "net45": { + "aspnet50": { "dependencies": { "System.Net.Http": "", "System.Net.Http.WebRequest": "", From 400b561958023a3b47ff9d4d220ddac77cc08656 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 5 Sep 2014 01:53:04 -0700 Subject: [PATCH 106/597] Updated build.cmd --- build.cmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.cmd b/build.cmd index 3aaf957583..86ca5bbbf1 100644 --- a/build.cmd +++ b/build.cmd @@ -20,9 +20,9 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion IF "%SKIP_KRE_INSTALL%"=="1" goto run -CALL packages\KoreBuild\build\kvm upgrade -svr50 -x86 -CALL packages\KoreBuild\build\kvm install default -svrc50 -x86 +CALL packages\KoreBuild\build\kvm upgrade -runtime CLR -x86 +CALL packages\KoreBuild\build\kvm install default -runtime CoreCLR -x86 :run -CALL packages\KoreBuild\build\kvm use default -svr50 -x86 +CALL packages\KoreBuild\build\kvm use default -runtime CLR -x86 packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* From 9fc4e8704bba307fdf1cd3a96e6b1cbb4e86faa9 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 8 Sep 2014 16:06:51 -0700 Subject: [PATCH 107/597] #62 - Abort the request for read/write failures. --- .../RequestProcessing/RequestContext.cs | 2 +- .../RequestProcessing/RequestStream.cs | 10 +++++ .../RequestStreamAsyncResult.cs | 1 + .../RequestProcessing/ResponseStream.cs | 40 +++++++++---------- .../ResponseStreamAsyncResult.cs | 3 +- 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 337959c064..37102f41a2 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -411,7 +411,7 @@ namespace Microsoft.Net.Http.Server context.Abort(); } - // This is only called while processing incoming requests. We don't have to worry about cancelling + // This is only called while processing incoming requests. We don't have to worry about canceling // any response writes. [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = "It is safe to ignore the return value on a cancel operation because the connection is being closed")] diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 46aa6db146..d84ff59a73 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -107,6 +107,12 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } + internal void Abort() + { + _closed = true; + _requestContext.Abort(); + } + private void ValidateReadBuffer(byte[] buffer, int offset, int size) { if (buffer == null) @@ -174,6 +180,7 @@ namespace Microsoft.Net.Http.Server { Exception exception = new WebListenerException((int)statusCode); LogHelper.LogException(_requestContext.Logger, "Read", exception); + Abort(); throw exception; } UpdateAfterRead(statusCode, dataRead); @@ -270,6 +277,7 @@ namespace Microsoft.Net.Http.Server { Exception exception = new WebListenerException((int)statusCode); LogHelper.LogException(_requestContext.Logger, "BeginRead", exception); + Abort(); throw exception; } } @@ -376,6 +384,7 @@ namespace Microsoft.Net.Http.Server catch (Exception e) { asyncResult.Dispose(); + Abort(); LogHelper.LogException(_requestContext.Logger, "ReadAsync", e); throw; } @@ -394,6 +403,7 @@ namespace Microsoft.Net.Http.Server { Exception exception = new WebListenerException((int)statusCode); LogHelper.LogException(_requestContext.Logger, "ReadAsync", exception); + Abort(); throw exception; } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs index effc75c6f7..d0218466cb 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs @@ -166,6 +166,7 @@ namespace Microsoft.Net.Http.Server } } Dispose(); + _requestStream.Abort(); } [SuppressMessage("Microsoft.Usage", "CA2216:DisposableTypesShouldDeclareFinalizer", Justification = "The disposable resource referenced does have a finalizer.")] diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 3a5b85699d..4bea85040b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -119,8 +119,7 @@ namespace Microsoft.Net.Http.Server catch (Exception e) { LogHelper.LogException(_requestContext.Logger, "Flush", e); - _closed = true; - _requestContext.Abort(); + Abort(); throw; } } @@ -172,8 +171,7 @@ namespace Microsoft.Net.Http.Server { LogHelper.LogException(_requestContext.Logger, "FlushAsync", e); asyncResult.Dispose(); - _closed = true; - _requestContext.Abort(); + Abort(); throw; } @@ -211,6 +209,12 @@ namespace Microsoft.Net.Http.Server #endregion + internal void Abort() + { + _closed = true; + _requestContext.Abort(); + } + private UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS ComputeLeftToWrite(bool endOfRequest = false) { UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; @@ -349,8 +353,7 @@ namespace Microsoft.Net.Http.Server { Exception exception = new WebListenerException((int)statusCode); LogHelper.LogException(_requestContext.Logger, "Write", exception); - _closed = true; - _requestContext.Abort(); + Abort(); throw exception; } UpdateWritenCount(dataToWrite); @@ -428,8 +431,7 @@ namespace Microsoft.Net.Http.Server { LogHelper.LogException(_requestContext.Logger, "BeginWrite", e); asyncResult.Dispose(); - _closed = true; - _requestContext.Abort(); + Abort(); throw; } @@ -444,8 +446,7 @@ namespace Microsoft.Net.Http.Server { Exception exception = new WebListenerException((int)statusCode); LogHelper.LogException(_requestContext.Logger, "BeginWrite", exception); - _closed = true; - _requestContext.Abort(); + Abort(); throw exception; } } @@ -456,7 +457,7 @@ namespace Microsoft.Net.Http.Server asyncResult.IOCompleted(statusCode, bytesSent); } - // Last write, cache it for special cancelation handling. + // Last write, cache it for special cancellation handling. if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) { _lastWrite = asyncResult; @@ -488,14 +489,13 @@ namespace Microsoft.Net.Http.Server try { // wait & then check for errors - // TODO: Gracefull re-throw + // TODO: Graceful re-throw castedAsyncResult.Task.Wait(); } catch (Exception exception) { LogHelper.LogException(_requestContext.Logger, "EndWrite", exception); - _closed = true; - _requestContext.Abort(); + Abort(); throw; } } @@ -576,8 +576,7 @@ namespace Microsoft.Net.Http.Server { LogHelper.LogException(_requestContext.Logger, "WriteAsync", e); asyncResult.Dispose(); - _closed = true; - _requestContext.Abort(); + Abort(); throw; } @@ -592,8 +591,7 @@ namespace Microsoft.Net.Http.Server { Exception exception = new WebListenerException((int)statusCode); LogHelper.LogException(_requestContext.Logger, "WriteAsync", exception); - _closed = true; - _requestContext.Abort(); + Abort(); throw exception; } } @@ -699,8 +697,7 @@ namespace Microsoft.Net.Http.Server { LogHelper.LogException(_requestContext.Logger, "SendFileAsync", e); asyncResult.Dispose(); - _closed = true; - _requestContext.Abort(); + Abort(); throw; } @@ -715,8 +712,7 @@ namespace Microsoft.Net.Http.Server { Exception exception = new WebListenerException((int)statusCode); LogHelper.LogException(_requestContext.Logger, "SendFileAsync", exception); - _closed = true; - _requestContext.Abort(); + Abort(); throw exception; } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 1a14b15485..18b4952793 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -355,6 +355,7 @@ namespace Microsoft.Net.Http.Server } } Dispose(); + _responseStream.Abort(); } /*++ @@ -362,7 +363,7 @@ namespace Microsoft.Net.Http.Server GetChunkHeader A private utility routine to convert an integer to a chunk header, - which is an ASCII hex number followed by a CRLF. The header is retuned + which is an ASCII hex number followed by a CRLF. The header is returned as a byte array. Input: From d50923a730de560b043b77d643ac793be402eb59 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 10 Sep 2014 12:06:55 -0700 Subject: [PATCH 108/597] Handle IBuilder rename to IApplicationBuilder. --- samples/SelfHostServer/Startup.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 1956abba60..93251f2a1a 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -19,7 +19,6 @@ using System; using System.Net.WebSockets; using System.Text; using System.Threading; -using Microsoft.AspNet; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Server.WebListener; @@ -29,7 +28,7 @@ namespace SelfHostServer { public class Startup { - public void Configure(IBuilder app) + public void Configure(IApplicationBuilder app) { var info = (ServerInformation)app.Server; info.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationTypes.AllowAnonymous; From c1680e92d6e14501712cf1fd057471cbb7ebe608 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 11 Sep 2014 10:07:08 -0700 Subject: [PATCH 109/597] Reacting to System.Text.Encoding package version change --- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- src/Microsoft.Net.WebSockets/project.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 2951f53f89..591611cf37 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -35,7 +35,7 @@ "System.Security.Claims": "1.0.0-*", "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.20.0", + "System.Text.Encoding": "4.0.10.0", "System.Text.Encoding.Extensions": "4.0.10.0", "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index cb314b1c30..f9abeb9eea 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -32,7 +32,7 @@ "System.Security.Claims": "1.0.0-*", "System.Security.Cryptography.X509Certificates": "4.0.0.0", "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.20.0", + "System.Text.Encoding": "4.0.10.0", "System.Text.Encoding.Extensions": "4.0.10.0", "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index b61f880017..8a03bfb293 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -27,7 +27,7 @@ "System.Security.Cryptography.Encryption": "4.0.0.0", "System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0", "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.20.0", + "System.Text.Encoding": "4.0.10.0", "System.Text.Encoding.Extensions": "4.0.10.0", "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", From 736fc684e6b85cb4e64056a1ae30043d98319d4e Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 14 Sep 2014 21:53:30 -0700 Subject: [PATCH 110/597] Work around build failures --- .../RequestProcessing/RequestStream.cs | 2 +- .../RequestProcessing/ResponseStream.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index d84ff59a73..de77301209 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -358,7 +358,7 @@ namespace Microsoft.Net.Http.Server size = MaxReadSize; } - CancellationTokenRegistration cancellationRegistration; + var cancellationRegistration = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 4bea85040b..4be40d6c69 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -139,7 +139,7 @@ namespace Microsoft.Net.Http.Server return Helpers.CanceledTask(); } - CancellationTokenRegistration cancellationRegistration; + var cancellationRegistration = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); @@ -534,7 +534,7 @@ namespace Microsoft.Net.Http.Server return Helpers.CanceledTask(); } - CancellationTokenRegistration cancellationRegistration; + var cancellationRegistration = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); @@ -640,7 +640,7 @@ namespace Microsoft.Net.Http.Server return Helpers.CanceledTask(); } - CancellationTokenRegistration cancellationRegistration; + var cancellationRegistration = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); From 0139bea6d21e3fdb4e442aeafdce5f6ae9869f65 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 12 Sep 2014 15:38:02 -0700 Subject: [PATCH 111/597] #56 - Make Request & Response Stream throw IOException. --- .../RequestProcessing/RequestStream.cs | 6 +++--- .../RequestStreamAsyncResult.cs | 3 ++- .../RequestProcessing/ResponseStream.cs | 16 ++++++++-------- .../ResponseStreamAsyncResult.cs | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index de77301209..0beaf04cda 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -178,7 +178,7 @@ namespace Microsoft.Net.Http.Server } if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - Exception exception = new WebListenerException((int)statusCode); + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "Read", exception); Abort(); throw exception; @@ -275,7 +275,7 @@ namespace Microsoft.Net.Http.Server } else { - Exception exception = new WebListenerException((int)statusCode); + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "BeginRead", exception); Abort(); throw exception; @@ -401,7 +401,7 @@ namespace Microsoft.Net.Http.Server } else { - Exception exception = new WebListenerException((int)statusCode); + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "ReadAsync", exception); Abort(); throw exception; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs index d0218466cb..6976d21725 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs @@ -23,6 +23,7 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -109,7 +110,7 @@ namespace Microsoft.Net.Http.Server { if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - asyncResult.Fail(new WebListenerException((int)errorCode)); + asyncResult.Fail(new IOException(string.Empty, new WebListenerException((int)errorCode))); } else { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 4be40d6c69..6b428a29d5 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -113,7 +113,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - throw new WebListenerException((int)statusCode); + throw new IOException(string.Empty, new WebListenerException((int)statusCode)); } } catch (Exception e) @@ -164,7 +164,7 @@ namespace Microsoft.Net.Http.Server } else if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) { - throw new WebListenerException((int)statusCode); + throw new IOException(string.Empty, new WebListenerException((int)statusCode)); } } catch (Exception e) @@ -351,7 +351,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - Exception exception = new WebListenerException((int)statusCode); + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "Write", exception); Abort(); throw exception; @@ -444,7 +444,7 @@ namespace Microsoft.Net.Http.Server } else { - Exception exception = new WebListenerException((int)statusCode); + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "BeginWrite", exception); Abort(); throw exception; @@ -589,7 +589,7 @@ namespace Microsoft.Net.Http.Server } else { - Exception exception = new WebListenerException((int)statusCode); + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "WriteAsync", exception); Abort(); throw exception; @@ -602,7 +602,7 @@ namespace Microsoft.Net.Http.Server asyncResult.IOCompleted(statusCode, bytesSent); } - // Last write, cache it for special cancelation handling. + // Last write, cache it for special cancellation handling. if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) { _lastWrite = asyncResult; @@ -710,7 +710,7 @@ namespace Microsoft.Net.Http.Server } else { - Exception exception = new WebListenerException((int)statusCode); + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "SendFileAsync", exception); Abort(); throw exception; @@ -829,7 +829,7 @@ namespace Microsoft.Net.Http.Server // Don't throw for disconnects, we were already finished with the response. && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID) { - Exception exception = new WebListenerException((int)statusCode); + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "Dispose", exception); _requestContext.Abort(); throw exception; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 18b4952793..d1dfc1bb9e 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -291,7 +291,7 @@ namespace Microsoft.Net.Http.Server { if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - asyncResult.Fail(new WebListenerException((int)errorCode)); + asyncResult.Fail(new IOException(string.Empty, new WebListenerException((int)errorCode))); } else { From 5f7c06d0ec23db6fb83b0a0e48bc293b5e8e5767 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 15 Sep 2014 14:20:56 -0700 Subject: [PATCH 112/597] Fix request stream tests. --- .../RequestBodyTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index d7ca42c3c9..606aa6c169 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -258,7 +258,7 @@ namespace Microsoft.Net.Http.Server var readTask = context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); Assert.False(readTask.IsCanceled); cts.Cancel(); - await Assert.ThrowsAsync(async () => await readTask); + await Assert.ThrowsAsync(async () => await readTask); content.Block.Release(); context.Dispose(); @@ -283,7 +283,7 @@ namespace Microsoft.Net.Http.Server cts.CancelAfter(TimeSpan.FromMilliseconds(100)); var readTask = context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); Assert.False(readTask.IsCanceled); - await Assert.ThrowsAsync(async () => await readTask); + await Assert.ThrowsAsync(async () => await readTask); content.Block.Release(); context.Dispose(); @@ -308,7 +308,7 @@ namespace Microsoft.Net.Http.Server int read = await context.Request.Body.ReadAsync(input, 0, input.Length, context.DisconnectToken); Assert.False(context.DisconnectToken.IsCancellationRequested); // The client should timeout and disconnect, making this read fail. - var assertTask = Assert.ThrowsAsync(async () => await context.Request.Body.ReadAsync(input, 0, input.Length, context.DisconnectToken)); + var assertTask = Assert.ThrowsAsync(async () => await context.Request.Body.ReadAsync(input, 0, input.Length, context.DisconnectToken)); client.CancelPendingRequests(); await assertTask; content.Block.Release(); From c8c6b4e02ddb1aeae270b039fc3ff29126a547f2 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 17 Sep 2014 09:22:09 -0700 Subject: [PATCH 113/597] Suppress InvalidParameter errors on respone Dispose for aborted requests. --- .../RequestProcessing/ResponseStream.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 6b428a29d5..94c20b00d1 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -827,7 +827,8 @@ namespace Microsoft.Net.Http.Server } if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF // Don't throw for disconnects, we were already finished with the response. - && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID) + && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID + && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER) { Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(_requestContext.Logger, "Dispose", exception); From 4062014cc6eb78cf3582d071ac8c78ed6e4d9873 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 17 Sep 2014 10:00:56 -0700 Subject: [PATCH 114/597] Updating release NuGet.config --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index f41e9c631d..1ce6b9e257 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@ - + - + From 281ef61e8c269db450c226bef22f6054dc0c0d9b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 17 Sep 2014 10:00:58 -0700 Subject: [PATCH 115/597] Updating dev NuGet.config --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index 1ce6b9e257..f41e9c631d 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@ - + - + From 56483cb0ed43412d7024d3ca991ed9973509f06b Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 17 Sep 2014 11:06:12 -0700 Subject: [PATCH 116/597] #54 - Throw if anyone tries to modify the response headers after they are sent. --- samples/SelfHostServer/Startup.cs | 2 +- .../RequestProcessing/HeaderCollection.cs | 29 +++++++++++++++++-- .../RequestProcessing/Response.cs | 1 + .../ResponseHeaderTests.cs | 4 +-- .../OpaqueUpgradeTests.cs | 2 +- .../ResponseHeaderTests.cs | 12 +++++--- 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 93251f2a1a..f4302222b9 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -47,7 +47,7 @@ namespace SelfHostServer else { context.Response.ContentType = "text/plain"; - await context.Response.WriteAsync("Hello world"); + await context.Response.WriteAsync("Hello world from " + context.Request.Host + " at " + DateTime.Now); } }); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs index 52eaa6e33b..4699dbd1e1 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs @@ -21,11 +21,15 @@ namespace Microsoft.Net.Http.Server private IDictionary Store { get; set; } + // Readonly after the response has been sent. + internal bool Sent { get; set; } + public string this[string key] { get { return Get(key); } set { + ThrowIfSent(); if (string.IsNullOrEmpty(value)) { Remove(key); @@ -40,7 +44,11 @@ namespace Microsoft.Net.Http.Server string[] IDictionary.this[string key] { get { return Store[key]; } - set { Store[key] = value; } + set + { + ThrowIfSent(); + Store[key] = value; + } } public int Count @@ -50,7 +58,7 @@ namespace Microsoft.Net.Http.Server public bool IsReadOnly { - get { return false; } + get { return Sent; } } public ICollection Keys @@ -65,16 +73,19 @@ namespace Microsoft.Net.Http.Server public void Add(KeyValuePair item) { + ThrowIfSent(); Store.Add(item); } public void Add(string key, string[] value) { + ThrowIfSent(); Store.Add(key, value); } public void Append(string key, string value) { + ThrowIfSent(); string[] values; if (Store.TryGetValue(key, out values)) { @@ -91,6 +102,7 @@ namespace Microsoft.Net.Http.Server public void AppendValues(string key, params string[] values) { + ThrowIfSent(); string[] oldValues; if (Store.TryGetValue(key, out oldValues)) { @@ -107,6 +119,7 @@ namespace Microsoft.Net.Http.Server public void Clear() { + ThrowIfSent(); Store.Clear(); } @@ -152,21 +165,25 @@ namespace Microsoft.Net.Http.Server public bool Remove(KeyValuePair item) { + ThrowIfSent(); return Store.Remove(item); } public bool Remove(string key) { + ThrowIfSent(); return Store.Remove(key); } public void Set(string key, string value) { + ThrowIfSent(); Store[key] = new[] { value }; } public void SetValues(string key, params string[] values) { + ThrowIfSent(); Store[key] = values; } @@ -179,5 +196,13 @@ namespace Microsoft.Net.Http.Server { return GetEnumerator(); } + + private void ThrowIfSent() + { + if (Sent) + { + throw new InvalidOperationException("The response headers cannot be modified because they have already been sent."); + } + } } } \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 28ea172d40..b85010f985 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -583,6 +583,7 @@ namespace Microsoft.Net.Http.Server private List SerializeHeaders(bool isOpaqueUpgrade) { + Headers.Sent = true; // Prohibit further modifications. UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; List pinnedHeaders; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index c086ce3cea..66b18b3364 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -247,7 +247,7 @@ namespace Microsoft.AspNet.Server.WebListener var body = responseInfo.Body; body.Flush(); Assert.Throws(() => responseInfo.StatusCode = 404); - responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored + Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); return Task.FromResult(0); })) { @@ -277,7 +277,7 @@ namespace Microsoft.AspNet.Server.WebListener var body = responseInfo.Body; await body.FlushAsync(); Assert.Throws(() => responseInfo.StatusCode = 404); - responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored + Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); })) { HttpResponseMessage response = await SendRequestAsync(address); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index e3076cff0f..d6dc580fc2 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -24,7 +24,7 @@ namespace Microsoft.Net.Http.Server byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.Body.Write(body, 0, body.Length); - context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket + Assert.Throws(() => context.Response.Headers["Upgrade"] = "WebSocket"); // Win8.1 blocks anything but WebSocket await Assert.ThrowsAsync(async () => await context.UpgradeAsync()); context.Dispose(); HttpResponseMessage response = await clientTask; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index 8b0dad5460..3059532f5d 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -233,8 +233,10 @@ namespace Microsoft.Net.Http.Server responseHeaders.SetValues("Custom2", "value2a, value2b"); var body = context.Response.Body; body.Flush(); - Assert.Throws(() => context.Response.StatusCode = 404); - responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored + var ex = Assert.Throws(() => context.Response.StatusCode = 404); + Assert.Equal("Headers already sent.", ex.Message); + ex = Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); + Assert.Equal("The response headers cannot be modified because they have already been sent.", ex.Message); context.Dispose(); @@ -265,8 +267,10 @@ namespace Microsoft.Net.Http.Server responseHeaders.SetValues("Custom2", "value2a, value2b"); var body = context.Response.Body; await body.FlushAsync(); - Assert.Throws(() => context.Response.StatusCode = 404); - responseHeaders.SetValues("Custom3", "value3a, value3b", "value3c"); // Ignored + var ex = Assert.Throws(() => context.Response.StatusCode = 404); + Assert.Equal("Headers already sent.", ex.Message); + ex = Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); + Assert.Equal("The response headers cannot be modified because they have already been sent.", ex.Message); context.Dispose(); From 4d2b2a14d521c593038b539edcc3f7cdf8e250d5 Mon Sep 17 00:00:00 2001 From: jhawk42 Date: Wed, 26 Mar 2014 11:20:07 -0700 Subject: [PATCH 117/597] Win7PlusCoreSystem --- .../NativeInterop/UnsafeNativeMethods.cs | 33 +++++++++++ .../NativeInterop/UnsafeNativeMethods.cs | 59 ++++++++++++++++++- .../fx/System/ExternDll.cs | 6 +- .../fx/System/SafeNativeMethods.cs | 5 +- .../NativeInterop/UnsafeNativeMethods.cs | 12 ++++ .../fx/System/ExternDll.cs | 6 +- .../fx/System/SafeNativeMethods.cs | 5 +- 7 files changed, 120 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs index 2eebb1d6a9..7084e0e206 100644 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs @@ -32,13 +32,26 @@ namespace Microsoft.AspNet.Security.Windows [System.Security.SuppressUnmanagedCodeSecurityAttribute] internal static class UnsafeNclNativeMethods { +#if ASPNETCORE50 + private const string sspicli_LIB = "sspicli.dll"; + private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; + private const string api_ms_win_core_handle_LIB = "api-ms-win-core-handle-l1-1-0.dll"; + private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-1.dll"; + private const string api_ms_win_core_heap_obsolete_LIB = "api-ms-win-core-heap-obsolete-l1-1-0.dll"; +#else private const string KERNEL32 = "kernel32.dll"; +#endif private const string SECUR32 = "secur32.dll"; private const string CRYPT32 = "crypt32.dll"; +#if ASPNETCORE50 + [DllImport(api_ms_win_core_processthreads_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] +#endif internal static extern uint GetCurrentThreadId(); + [System.Security.SuppressUnmanagedCodeSecurityAttribute] internal static class SafeNetHandles { @@ -164,18 +177,34 @@ namespace Microsoft.AspNet.Security.Windows [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] internal static extern int QuerySecurityContextToken(ref SSPIHandle phContext, [Out] out SafeCloseHandle handle); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal static extern bool CloseHandle(IntPtr handle); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal static extern IntPtr LocalFree(IntPtr handle); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); @@ -194,7 +223,11 @@ namespace Microsoft.AspNet.Security.Windows internal static extern bool CertFreeCertificateContext( // Suppressing returned status check, it's always==TRUE, [In] IntPtr certContext); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal static extern IntPtr GlobalFree(IntPtr handle); } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index 641b25e963..cac47b387d 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -30,10 +30,20 @@ namespace Microsoft.Net.Http.Server { internal static class UnsafeNclNativeMethods { - private const string KERNEL32 = "kernel32.dll"; - private const string SECUR32 = "secur32.dll"; private const string HTTPAPI = "httpapi.dll"; +#if ASPNETCORE50 + private const string sspicli_LIB = "sspicli.dll"; + private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; + private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-1.dll"; + private const string api_ms_win_core_handle_LIB = "api-ms-win-core-handle-l1-1-0.dll"; + private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-1.dll"; + private const string api_ms_win_core_heap_obsolete_LIB = "api-ms-win-core-heap-obsolete-L1-1-0.dll"; + private const string api_ms_win_core_kernel32_legacy_LIB = "api-ms-win-core-kernel32-legacy-l1-1-0.dll"; +#else + private const string KERNEL32 = "kernel32.dll"; + private const string SECUR32 = "secur32.dll"; +#endif // CONSIDER: Make this an enum, requires changing a lot of types from uint to ErrorCodes. internal static class ErrorCodes { @@ -49,13 +59,25 @@ namespace Microsoft.Net.Http.Server internal const uint ERROR_CONNECTION_INVALID = 1229; } +#if ASPNETCORE50 + [DllImport(api_ms_win_core_processthreads_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] +#endif internal static extern uint GetCurrentThreadId(); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_io_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] +#endif internal static unsafe extern uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_kernel32_legacy_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] +#endif internal static unsafe extern bool SetFileCompletionNotificationModes(SafeHandle handle, FileCompletionNotificationModes modes); [Flags] @@ -68,11 +90,19 @@ namespace Microsoft.Net.Http.Server internal static class SafeNetHandles { +#if ASPNETCORE50 + [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] +#endif internal static extern int FreeContextBuffer( [In] IntPtr contextBuffer); +#if ASPNETCORE50 + [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] +#endif internal static unsafe extern int QueryContextAttributesW( ref SSPIHandle contextHandle, [In] ContextAttribute attribute, @@ -85,22 +115,47 @@ namespace Microsoft.Net.Http.Server [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif internal static extern bool CloseHandle(IntPtr handle); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_heap_obsolete_LIB, EntryPoint = "LocalAlloc", SetLastError = true)] +#else [DllImport(KERNEL32, EntryPoint = "LocalAlloc", SetLastError = true)] +#endif + internal static extern SafeLocalFreeChannelBinding LocalAllocChannelBinding(int uFlags, UIntPtr sizetdwBytes); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif internal static extern IntPtr LocalFree(IntPtr handle); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] +#endif internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); } diff --git a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs index 693cecaf1d..50235a6447 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs @@ -27,7 +27,11 @@ namespace System { internal static class ExternDll { +#if ASPNETCORE50 + public const string api_ms_win_core_localization_LIB = "api-ms-win-core-localization-l2-1-0.dll"; +#else public const string Kernel32 = "kernel32.dll"; +#endif } } -#endif +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs index 098a797cdd..da9548c88b 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs @@ -36,10 +36,13 @@ namespace System FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; +#if ASPNETCORE50 + [DllImport(ExternDll.api_ms_win_core_localization_LIB, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] +#else [DllImport(ExternDll.Kernel32, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] +#endif public static unsafe extern int FormatMessage(int dwFlags, IntPtr lpSource_mustBeNull, uint dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr[] arguments); - } } #endif diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs index de2d07588f..f522002f8b 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -31,15 +31,27 @@ namespace Microsoft.Net.WebSockets { internal static class UnsafeNativeMethods { +#if ASPNETCORE50 + private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-1.dll"; +#else private const string KERNEL32 = "kernel32.dll"; +#endif private const string WEBSOCKET = "websocket.dll"; internal static class SafeNetHandles { +#if ASPNETCORE50 + [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, CharSet=CharSet.Unicode, SetLastError = true)] +#endif internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); +#if ASPNETCORE50 + [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] +#else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); } diff --git a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs index 693cecaf1d..c1e1f5b20f 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs @@ -27,7 +27,11 @@ namespace System { internal static class ExternDll { +#if NETFX || ASPNET50 public const string Kernel32 = "kernel32.dll"; +#else + public const string api_ms_win_core_localization_LIB = "api-ms-win-core-localization-l2-1-0.dll"; +#endif } } -#endif +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs index 098a797cdd..7ee12dbbdc 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs @@ -36,10 +36,13 @@ namespace System FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; +#if ASPNETCORE50 + [DllImport(ExternDll.api_ms_win_core_localization_LIB, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] +#else [DllImport(ExternDll.Kernel32, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] +#endif public static unsafe extern int FormatMessage(int dwFlags, IntPtr lpSource_mustBeNull, uint dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr[] arguments); - } } #endif From 66144c864e62113b55050a4fda3a8bd4955dc401 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 24 Sep 2014 11:33:47 -0700 Subject: [PATCH 118/597] #67 - Fire disconnect notifications even for gracefull disconnects. --- .../NativeInterop/UnsafeNativeMethods.cs | 2 +- src/Microsoft.Net.Http.Server/WebListener.cs | 2 +- .../ServerTests.cs | 118 ++++++++---------- 3 files changed, 56 insertions(+), 66 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index cac47b387d..3d005ba6b7 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -193,7 +193,7 @@ namespace Microsoft.Net.Http.Server internal static extern uint HttpSendResponseEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, IntPtr pEntityChunks, out uint pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeHandle pOverlapped, IntPtr pLogData); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpWaitForDisconnect(SafeHandle requestQueueHandle, ulong connectionId, SafeNativeOverlapped pOverlapped); + internal static extern uint HttpWaitForDisconnectEx(SafeHandle requestQueueHandle, ulong connectionId, uint reserved, SafeNativeOverlapped overlapped); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpCreateServerSession(HTTPAPI_VERSION version, ulong* serverSessionId, uint reserved); diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index d68eceb01d..e897f05e42 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -768,7 +768,7 @@ namespace Microsoft.Net.Http.Server uint statusCode; try { - statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect(_requestQueueHandle, connectionId, nativeOverlapped); + statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnectEx(_requestQueueHandle, connectionId, 0, nativeOverlapped); } catch (Win32Exception exception) { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 23c641dea3..f4abdb333d 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -81,24 +81,25 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - // Note: System.Net.Sockets does not RST the connection by default, it just FINs. - // Http.Sys's disconnect notice requires a RST. - Task responseTask = SendHungRequestAsync("GET", address); - - var context = await server.GetContextAsync(); - CancellationToken ct = context.DisconnectToken; - Assert.True(ct.CanBeCanceled, "CanBeCanceled"); - Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); - ct.Register(() => canceled.Set()); - - using (Socket socket = await responseTask) + using (var client = new HttpClient()) { - socket.Close(0); // Force a RST - } - Assert.True(canceled.WaitOne(interval), "canceled"); - Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); + Task responseTask = client.GetAsync(address); - context.Dispose(); + var context = await server.GetContextAsync(); + CancellationToken ct = context.DisconnectToken; + Assert.True(ct.CanBeCanceled, "CanBeCanceled"); + Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); + ct.Register(() => canceled.Set()); + + client.CancelPendingRequests(); + + Assert.True(canceled.WaitOne(interval), "canceled"); + Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); + + await Assert.ThrowsAsync(() => responseTask); + + context.Dispose(); + } } } @@ -111,9 +112,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - // Note: System.Net.Sockets does not RST the connection by default, it just FINs. - // Http.Sys's disconnect notice requires a RST. - Task responseTask = SendHungRequestAsync("GET", address); + var responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); CancellationToken ct = context.DisconnectToken; @@ -124,10 +123,44 @@ namespace Microsoft.Net.Http.Server Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - using (Socket socket = await responseTask) + // HttpClient re-tries the request because it doesn't know if the request was received. + context = await server.GetContextAsync(); + context.Abort(); + + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task Server_ConnectionCloseHeader_CancellationTokenFires() + { + TimeSpan interval = TimeSpan.FromSeconds(1); + ManualResetEvent canceled = new ManualResetEvent(false); + + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + CancellationToken ct = context.DisconnectToken; + Assert.True(ct.CanBeCanceled, "CanBeCanceled"); + Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); + ct.Register(() => canceled.Set()); + + context.Response.Headers["Connection"] = "close"; + + context.Response.ContentLength = 11; + using (var writer = new StreamWriter(context.Response.Body)) { - Assert.Throws(() => socket.Receive(new byte[10])); + writer.Write("Hello World"); } + + Assert.True(canceled.WaitOne(interval), "Disconnected"); + Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); + + string response = await responseTask; + Assert.Equal("Hello World", response); } } @@ -166,48 +199,5 @@ namespace Microsoft.Net.Http.Server return await response.Content.ReadAsStringAsync(); } } - - private async Task SendHungRequestAsync(string method, string address) - { - // Connect with a socket - Uri uri = new Uri(address); - TcpClient client = new TcpClient(); - try - { - await client.ConnectAsync(uri.Host, uri.Port); - NetworkStream stream = client.GetStream(); - - // Send an HTTP GET request - byte[] requestBytes = BuildGetRequest(method, uri); - await stream.WriteAsync(requestBytes, 0, requestBytes.Length); - - // Return the opaque network stream - return client.Client; - } - catch (Exception) - { - client.Close(); - throw; - } - } - - private byte[] BuildGetRequest(string method, Uri uri) - { - StringBuilder builder = new StringBuilder(); - builder.Append(method); - builder.Append(" "); - builder.Append(uri.PathAndQuery); - builder.Append(" HTTP/1.1"); - builder.AppendLine(); - - builder.Append("Host: "); - builder.Append(uri.Host); - builder.Append(':'); - builder.Append(uri.Port); - builder.AppendLine(); - - builder.AppendLine(); - return Encoding.ASCII.GetBytes(builder.ToString()); - } } } From 88da31af7c6bafece196a6f94b33324ea538b276 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 25 Sep 2014 15:36:40 -0700 Subject: [PATCH 119/597] Cleanup. --- src/Microsoft.Net.Http.Server/WebListener.cs | 3 +- .../ServerTests.cs | 57 ++++++++----------- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index e897f05e42..11288670c3 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -768,7 +768,8 @@ namespace Microsoft.Net.Http.Server uint statusCode; try { - statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnectEx(_requestQueueHandle, connectionId, 0, nativeOverlapped); + statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnectEx(requestQueueHandle: _requestQueueHandle, + connectionId: connectionId, reserved: 0, overlapped: nativeOverlapped); } catch (Win32Exception exception) { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index f4abdb333d..e66e1f768e 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -17,15 +17,14 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_200OK_Success() { - string address; - using (var server = Utilities.CreateHttpServer(out address)) + using (var server = Utilities.CreateHttpServer(out var address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Dispose(); - string response = await responseTask; + var response = await responseTask; Assert.Equal(string.Empty, response); } } @@ -33,8 +32,7 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_SendHelloWorld_Success() { - string address; - using (var server = Utilities.CreateHttpServer(out address)) + using (var server = Utilities.CreateHttpServer(out var address)) { Task responseTask = SendRequestAsync(address); @@ -53,10 +51,9 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_EchoHelloWorld_Success() { - string address; - using (var server = Utilities.CreateHttpServer(out address)) + using (var server = Utilities.CreateHttpServer(out var address)) { - Task responseTask = SendRequestAsync(address, "Hello World"); + var responseTask = SendRequestAsync(address, "Hello World"); var context = await server.GetContextAsync(); string input = new StreamReader(context.Request.Body).ReadToEnd(); @@ -67,7 +64,7 @@ namespace Microsoft.Net.Http.Server writer.Write("Hello World"); } - string response = await responseTask; + var response = await responseTask; Assert.Equal("Hello World", response); } } @@ -75,18 +72,17 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_ClientDisconnects_CallCanceled() { - TimeSpan interval = TimeSpan.FromSeconds(1); - ManualResetEvent canceled = new ManualResetEvent(false); + var interval = TimeSpan.FromSeconds(1); + var canceled = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address)) + using (var server = Utilities.CreateHttpServer(out var address)) { using (var client = new HttpClient()) { - Task responseTask = client.GetAsync(address); + var responseTask = client.GetAsync(address); var context = await server.GetContextAsync(); - CancellationToken ct = context.DisconnectToken; + var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); ct.Register(() => canceled.Set()); @@ -106,16 +102,15 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_Abort_CallCanceled() { - TimeSpan interval = TimeSpan.FromSeconds(1); - ManualResetEvent canceled = new ManualResetEvent(false); + var interval = TimeSpan.FromSeconds(1); + var canceled = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address)) + using (var server = Utilities.CreateHttpServer(out var address)) { var responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); - CancellationToken ct = context.DisconnectToken; + var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); ct.Register(() => canceled.Set()); @@ -134,16 +129,15 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_ConnectionCloseHeader_CancellationTokenFires() { - TimeSpan interval = TimeSpan.FromSeconds(1); - ManualResetEvent canceled = new ManualResetEvent(false); + var interval = TimeSpan.FromSeconds(1); + var canceled = new ManualResetEvent(false); - string address; - using (var server = Utilities.CreateHttpServer(out address)) + using (var server = Utilities.CreateHttpServer(out var address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); - CancellationToken ct = context.DisconnectToken; + var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); ct.Register(() => canceled.Set()); @@ -159,7 +153,7 @@ namespace Microsoft.Net.Http.Server Assert.True(canceled.WaitOne(interval), "Disconnected"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - string response = await responseTask; + var response = await responseTask; Assert.Equal("Hello World", response); } } @@ -167,16 +161,15 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_SetQueueLimit_Success() { - string address; - using (var server = Utilities.CreateHttpServer(out address)) + using (var server = Utilities.CreateHttpServer(out var address)) { server.SetRequestQueueLimit(1001); - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); context.Dispose(); - string response = await responseTask; + var response = await responseTask; Assert.Equal(string.Empty, response); } } From 19b1db41decf4316ca02d72a23ab7766549d74ad Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 26 Sep 2014 11:40:56 -0700 Subject: [PATCH 120/597] Remove WindowsAuth middleware package. --- WebListener.sln | 15 +- .../AuthTypes.cs | 54 - .../ComNetOS.cs | 55 - .../Constants.cs | 60 - .../DictionaryExtensions.cs | 84 -- .../DigestCache.cs | 170 --- .../DisconnectAsyncResult.cs | 110 -- .../HeaderEncoding.cs | 156 -- .../HttpKnownHeaderNames.cs | 92 -- .../HttpStatusCode.cs | 331 ----- .../Legacy/CaseInsinsitiveAscii.cs | 150 -- .../Legacy/GlobalLog.cs | 706 --------- .../Legacy/HttpListenerContext.cs | 84 -- .../Legacy/Internal.cs | 303 ---- .../Legacy/Logging.cs | 674 --------- .../Legacy/LoggingObject.cs | 597 -------- .../Legacy/SR.cs | 647 -------- .../Legacy/ValidationHelper.cs | 91 -- .../Microsoft.AspNet.Security.Windows.kproj | 21 - .../NTAuthentication.cs | 738 ---------- .../NativeInterop/AuthIdentity.cs | 57 - .../NativeInterop/ContextFlags.cs | 141 -- .../NativeInterop/NativeSSPI.cs | 59 - .../NativeInterop/SSPIAuthType.cs | 319 ---- .../NativeInterop/SSPIHandle.cs | 53 - .../NativeInterop/SSPISessionCache.cs | 66 - .../NativeInterop/SSPIWrapper.cs | 479 ------ .../NativeInterop/SafeCloseHandle.cs | 68 - .../NativeInterop/SafeCredentialReference.cs | 86 -- .../NativeInterop/SafeDeleteContext.cs | 724 --------- .../NativeInterop/SafeFreeCertContext.cs | 52 - .../NativeInterop/SafeFreeContextBuffer.cs | 165 --- .../SafeFreeContextBufferChannelBinding.cs | 106 -- .../NativeInterop/SafeFreeCredentials.cs | 216 --- .../NativeInterop/SafeLocalFree.cs | 65 - .../NativeInterop/SafeSspiAuthDataHandle.cs | 49 - .../NativeInterop/SchProtocols.cs | 58 - .../NativeInterop/SecSizes.cs | 61 - .../NativeInterop/SecurityBuffer.cs | 73 - .../NativeInterop/SecurityBufferDescriptor.cs | 50 - .../NativeInterop/SecurityPackageInfoClass.cs | 97 -- .../NativeInterop/SslConnectionInfo.cs | 55 - .../NativeInterop/StreamSizes.cs | 60 - .../NativeInterop/UnsafeNativeMethods.cs | 272 ---- .../NegotiationInfoClass.cs | 87 -- .../PrefixCollection.cs | 126 -- .../PrefixEnumerator.cs | 68 - .../ServiceNameStore.cs | 385 ----- .../WindowsAuthMiddleware.cs | 1298 ----------------- .../project.json | 13 - 50 files changed, 1 insertion(+), 10545 deletions(-) delete mode 100644 src/Microsoft.AspNet.Security.Windows/AuthTypes.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/ComNetOS.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Constants.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/DigestCache.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj delete mode 100644 src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs delete mode 100644 src/Microsoft.AspNet.Security.Windows/project.json diff --git a/WebListener.sln b/WebListener.sln index a27e04c6b7..c55169b1f2 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.21916.0 +VisualStudioVersion = 14.0.22115.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -17,8 +17,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\Hello EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.kproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Security.Windows", "src\Microsoft.AspNet.Security.Windows\Microsoft.AspNet.Security.Windows.kproj", "{EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}" -EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.WebSockets", "src\Microsoft.Net.WebSockets\Microsoft.Net.WebSockets.kproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj", "{4492FF4C-9032-411D-853F-46B01755E504}" @@ -82,16 +80,6 @@ Global {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.Build.0 = Release|Any CPU {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|x86.ActiveCfg = Release|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Debug|x86.ActiveCfg = Debug|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Any CPU.Build.0 = Release|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF}.Release|x86.ActiveCfg = Release|Any CPU {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Any CPU.Build.0 = Debug|Any CPU {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -141,7 +129,6 @@ Global {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {1236F93A-AC5C-4A77-9477-C88F040151CA} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {EFC7538F-7AEB-4A3E-A1E6-6BDCCBD272BF} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {4492FF4C-9032-411D-853F-46B01755E504} = {E183C826-1360-4DFF-9994-F33CED5C8525} {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} diff --git a/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs b/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs deleted file mode 100644 index d7f768fe99..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/AuthTypes.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; - -namespace Microsoft.AspNet.Security.Windows -{ - /// - /// Types of Windows Authentication supported. - /// - [Flags] - public enum AuthTypes - { - /// - /// Default - /// - None = 0, - - /// - /// Digest authentication using Windows credentials - /// - Digest = 1, - - /// - /// Negotiates Kerberos or NTLM - /// - Negotiate = 2, - - /// - /// NTLM Windows authentication - /// - Ntlm = 4, - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs b/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs deleted file mode 100644 index e2acc2603b..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/ComNetOS.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Diagnostics; -using System.Runtime.Versioning; -using System.Security.Permissions; - -namespace Microsoft.AspNet.Security.Windows -{ - internal static class ComNetOS - { - // Minimum support for Windows 2008 is assumed. - internal static readonly bool IsWin7orLater; // Is Windows 7 or later - internal static readonly bool IsWin8orLater; // Is Windows 8 or later - - // We use it safe so assert - [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)] - [ResourceExposure(ResourceScope.None)] - [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)] - static ComNetOS() - { - OperatingSystem operatingSystem = Environment.OSVersion; - - GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString()); - - Debug.Assert(operatingSystem.Platform != PlatformID.Win32Windows, "Windows 9x is not supported"); - - var Win7Version = new Version(6, 1); - var Win8Version = new Version(6, 2); - IsWin7orLater = (operatingSystem.Version >= Win7Version); - IsWin8orLater = (operatingSystem.Version >= Win8Version); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/Constants.cs b/src/Microsoft.AspNet.Security.Windows/Constants.cs deleted file mode 100644 index f5f618cd83..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Constants.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace Microsoft.AspNet.Security.Windows -{ - internal static class Constants - { - internal const string VersionKey = "owin.Version"; - internal const string OwinVersion = "1.0"; - - internal const string RequestBodyKey = "owin.RequestBody"; - internal const string RequestHeadersKey = "owin.RequestHeaders"; - internal const string RequestSchemeKey = "owin.RequestScheme"; - internal const string RequestMethodKey = "owin.RequestMethod"; - internal const string RequestPathBaseKey = "owin.RequestPathBase"; - internal const string RequestPathKey = "owin.RequestPath"; - internal const string RequestQueryStringKey = "owin.RequestQueryString"; - internal const string HttpRequestProtocolKey = "owin.RequestProtocol"; - - internal const string HttpResponseProtocolKey = "owin.ResponseProtocol"; - internal const string ResponseStatusCodeKey = "owin.ResponseStatusCode"; - internal const string ResponseReasonPhraseKey = "owin.ResponseReasonPhrase"; - internal const string ResponseHeadersKey = "owin.ResponseHeaders"; - internal const string ResponseBodyKey = "owin.ResponseBody"; - - internal const string ClientCertifiateKey = "ssl.ClientCertificate"; - internal const string SslSpnKey = "ssl.Spn"; - internal const string SslChannelBindingKey = "ssl.ChannelBinding"; - - internal const string RemoteIpAddressKey = "server.RemoteIpAddress"; - internal const string RemotePortKey = "server.RemotePort"; - internal const string LocalIpAddressKey = "server.LocalIpAddress"; - internal const string LocalPortKey = "server.LocalPort"; - internal const string IsLocalKey = "server.IsLocal"; - internal const string ServerOnSendingHeadersKey = "server.OnSendingHeaders"; - internal const string ServerUserKey = "server.User"; - internal const string ServerConnectionIdKey = "server.ConnectionId"; - internal const string ServerConnectionDisconnectKey = "server.ConnectionDisconnect"; - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs b/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs deleted file mode 100644 index 2a627a5ae6..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/DictionaryExtensions.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Linq; -using System.Text; - -namespace System.Collections.Generic -{ - internal static class DictionaryExtensions - { - internal static void Append(this IDictionary dictionary, string key, string value) - { - string[] orriginalValues; - if (dictionary.TryGetValue(key, out orriginalValues)) - { - string[] newValues = new string[orriginalValues.Length + 1]; - orriginalValues.CopyTo(newValues, 0); - newValues[newValues.Length - 1] = value; - dictionary[key] = newValues; - } - else - { - dictionary[key] = new string[] { value }; - } - } - - internal static void Append(this IDictionary dictionary, string key, IList values) - { - string[] orriginalValues; - if (dictionary.TryGetValue(key, out orriginalValues)) - { - string[] newValues = new string[orriginalValues.Length + values.Count]; - orriginalValues.CopyTo(newValues, 0); - values.CopyTo(newValues, orriginalValues.Length); - dictionary[key] = newValues; - } - else - { - dictionary[key] = values.ToArray(); - } - } - - internal static string Get(this IDictionary dictionary, string key) - { - string[] values; - if (dictionary.TryGetValue(key, out values)) - { - return string.Join(", ", values); - } - return null; - } - - internal static T Get(this IDictionary dictionary, string key, T fallback = default(T)) - { - object values; - if (dictionary.TryGetValue(key, out values)) - { - return (T)values; - } - return fallback; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/DigestCache.cs b/src/Microsoft.AspNet.Security.Windows/DigestCache.cs deleted file mode 100644 index 4b9573c547..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/DigestCache.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Collections; -using System.Threading; - -namespace Microsoft.AspNet.Security.Windows -{ - // Saves generated digest challenges so that they are still valid when the authenticated request arrives. - internal class DigestCache : IDisposable - { - private const int DigestLifetimeSeconds = 300; - private const int MaximumDigests = 1024; // Must be a power of two. - private const int MinimumDigestLifetimeSeconds = 10; - - private DigestContext[] _savedDigests; - private ArrayList _extraSavedDigests; - private ArrayList _extraSavedDigestsBaking; - private int _extraSavedDigestsTimestamp; - private int _newestContext; - private int _oldestContext; - - internal DigestCache() - { - } - - internal void SaveDigestContext(NTAuthentication digestContext) - { - if (_savedDigests == null) - { - Interlocked.CompareExchange(ref _savedDigests, new DigestContext[MaximumDigests], null); - } - - // We want to actually close the contexts outside the lock. - NTAuthentication oldContext = null; - ArrayList digestsToClose = null; - lock (_savedDigests) - { - int now = ((now = Environment.TickCount) == 0 ? 1 : now); - - _newestContext = (_newestContext + 1) & (MaximumDigests - 1); - - int oldTimestamp = _savedDigests[_newestContext].timestamp; - oldContext = _savedDigests[_newestContext].context; - _savedDigests[_newestContext].timestamp = now; - _savedDigests[_newestContext].context = digestContext; - - // May need to move this up. - if (_oldestContext == _newestContext) - { - _oldestContext = (_newestContext + 1) & (MaximumDigests - 1); - } - - // Delete additional contexts older than five minutes. - while (unchecked(now - _savedDigests[_oldestContext].timestamp) >= DigestLifetimeSeconds && _savedDigests[_oldestContext].context != null) - { - if (digestsToClose == null) - { - digestsToClose = new ArrayList(); - } - digestsToClose.Add(_savedDigests[_oldestContext].context); - _savedDigests[_oldestContext].context = null; - _oldestContext = (_oldestContext + 1) & (MaximumDigests - 1); - } - - // If the old context is younger than 10 seconds, put it in the backup pile. - if (oldContext != null && unchecked(now - oldTimestamp) <= MinimumDigestLifetimeSeconds * 1000) - { - // Use a two-tier ArrayList system to guarantee each entry lives at least 10 seconds. - if (_extraSavedDigests == null || - unchecked(now - _extraSavedDigestsTimestamp) > MinimumDigestLifetimeSeconds * 1000) - { - digestsToClose = _extraSavedDigestsBaking; - _extraSavedDigestsBaking = _extraSavedDigests; - _extraSavedDigestsTimestamp = now; - _extraSavedDigests = new ArrayList(); - } - _extraSavedDigests.Add(oldContext); - oldContext = null; - } - } - - if (oldContext != null) - { - oldContext.CloseContext(); - } - if (digestsToClose != null) - { - for (int i = 0; i < digestsToClose.Count; i++) - { - ((NTAuthentication)digestsToClose[i]).CloseContext(); - } - } - } - - private void ClearDigestCache() - { - if (_savedDigests == null) - { - return; - } - - ArrayList[] toClose = new ArrayList[3]; - lock (_savedDigests) - { - toClose[0] = _extraSavedDigestsBaking; - _extraSavedDigestsBaking = null; - toClose[1] = _extraSavedDigests; - _extraSavedDigests = null; - - _newestContext = 0; - _oldestContext = 0; - - toClose[2] = new ArrayList(); - for (int i = 0; i < MaximumDigests; i++) - { - if (_savedDigests[i].context != null) - { - toClose[2].Add(_savedDigests[i].context); - _savedDigests[i].context = null; - } - _savedDigests[i].timestamp = 0; - } - } - - for (int j = 0; j < toClose.Length; j++) - { - if (toClose[j] != null) - { - for (int k = 0; k < toClose[j].Count; k++) - { - ((NTAuthentication)toClose[j][k]).CloseContext(); - } - } - } - } - - public void Dispose() - { - ClearDigestCache(); - } - - private struct DigestContext - { - internal NTAuthentication context; - internal int timestamp; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs b/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs deleted file mode 100644 index cb0feddc15..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/DisconnectAsyncResult.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Security.Principal; -using System.Threading; - -namespace Microsoft.AspNet.Security.Windows -{ - // Keeps NTLM/Negotiate auth contexts alive until the connection is broken. - internal class DisconnectAsyncResult - { - private const string NTLM = "NTLM"; - - private object _connectionId; - private WindowsAuthMiddleware _winAuth; - private CancellationTokenRegistration _disconnectRegistration; - - private WindowsPrincipal _authenticatedUser; - private NTAuthentication _session; - - internal DisconnectAsyncResult(WindowsAuthMiddleware winAuth, object connectionId, CancellationToken connectionDisconnect) - { - GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::.ctor() httpListener#" + ValidationHelper.HashString(winAuth) + " connectionId:" + connectionId); - _winAuth = winAuth; - _connectionId = connectionId; - _winAuth.DisconnectResults[_connectionId] = this; - - // Register with a connection specific CancellationToken. Without this notification, the contexts will leak indefinitely. - // Alternatively we could attempt some kind of LRU storage, but this will either have to be larger than your expected connection limit, - // or will fail at unexpected moments under stress. - try - { - _disconnectRegistration = connectionDisconnect.Register(HandleDisconnect); - } - catch (ObjectDisposedException) - { - _winAuth.DisconnectResults.Remove(_connectionId); - } - } - - internal WindowsPrincipal AuthenticatedUser - { - get - { - return _authenticatedUser; - } - set - { - // The previous value can't be disposed because it may be in use by the app. - _authenticatedUser = value; - } - } - - internal NTAuthentication Session - { - get - { - return _session; - } - set - { - _session = value; - } - } - - private void HandleDisconnect() - { - GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::HandleDisconnect() DisconnectResults#" + ValidationHelper.HashString(_winAuth.DisconnectResults) + " removing for m_ConnectionId:" + _connectionId); - _winAuth.DisconnectResults.Remove(_connectionId); - if (_session != null) - { - _session.CloseContext(); - } - - // Clean up the identity. This is for scenarios where identity was not cleaned up before due to - // identity caching for unsafe ntlm authentication - - IDisposable identity = _authenticatedUser == null ? null : _authenticatedUser.Identity as IDisposable; - if ((identity != null) && - (NTLM.Equals(_authenticatedUser.Identity.AuthenticationType, StringComparison.OrdinalIgnoreCase)) && - (_winAuth.UnsafeConnectionNtlmAuthentication)) - { - identity.Dispose(); - } - - _disconnectRegistration.Dispose(); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs b/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs deleted file mode 100644 index 331d79a80d..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/HeaderEncoding.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Text; - -namespace Microsoft.AspNet.Security.Windows -{ - // we use this static class as a helper class to encode/decode HTTP headers. - // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF - // and a byte in the range 0x00-0xFF (which is the range that can hit the network). - // The Latin-1 encoding (ISO-88591-1) (GetEncoding(28591)) works for byte[] to string, but is a little slow. - // It doesn't work for string -> byte[] because of best-fit-mapping problems. - internal static class HeaderEncoding - { - internal static unsafe string GetString(byte[] bytes, int byteIndex, int byteCount) - { - fixed (byte* pBytes = bytes) - return GetString(pBytes + byteIndex, byteCount); - } - - internal static unsafe string GetString(byte* pBytes, int byteCount) - { - if (byteCount < 1) - { - return string.Empty; - } - - string s = new String('\0', byteCount); - - fixed (char* pStr = s) - { - char* pString = pStr; - while (byteCount >= 8) - { - pString[0] = (char)pBytes[0]; - pString[1] = (char)pBytes[1]; - pString[2] = (char)pBytes[2]; - pString[3] = (char)pBytes[3]; - pString[4] = (char)pBytes[4]; - pString[5] = (char)pBytes[5]; - pString[6] = (char)pBytes[6]; - pString[7] = (char)pBytes[7]; - pString += 8; - pBytes += 8; - byteCount -= 8; - } - for (int i = 0; i < byteCount; i++) - { - pString[i] = (char)pBytes[i]; - } - } - - return s; - } - - internal static int GetByteCount(string myString) - { - return myString.Length; - } - internal static unsafe void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex) - { - if (myString.Length == 0) - { - return; - } - fixed (byte* bufferPointer = bytes) - { - byte* newBufferPointer = bufferPointer + byteIndex; - int finalIndex = charIndex + charCount; - while (charIndex < finalIndex) - { - *newBufferPointer++ = (byte)myString[charIndex++]; - } - } - } - internal static unsafe byte[] GetBytes(string myString) - { - byte[] bytes = new byte[myString.Length]; - if (myString.Length != 0) - { - GetBytes(myString, 0, myString.Length, bytes, 0); - } - return bytes; - } - - // The normal client header parser just casts bytes to chars (see GetString). - // Check if those bytes were actually utf-8 instead of ASCII. - // If not, just return the input value. - - internal static string DecodeUtf8FromString(string input) - { - if (string.IsNullOrWhiteSpace(input)) - { - return input; - } - - bool possibleUtf8 = false; - for (int i = 0; i < input.Length; i++) - { - if (input[i] > (char)255) - { - return input; // This couldn't have come from the wire, someone assigned it directly. - } - else if (input[i] > (char)127) - { - possibleUtf8 = true; - break; - } - } - if (possibleUtf8) - { - byte[] rawBytes = new byte[input.Length]; - for (int i = 0; i < input.Length; i++) - { - if (input[i] > (char)255) - { - return input; // This couldn't have come from the wire, someone assigned it directly. - } - rawBytes[i] = (byte)input[i]; - } - try - { - // We don't want '?' replacement characters, just fail. - Encoding decoder = Encoding.GetEncoding("utf-8", EncoderFallback.ExceptionFallback, - DecoderFallback.ExceptionFallback); - return decoder.GetString(rawBytes); - } - catch (ArgumentException) - { - } // Not actually Utf-8 - } - return input; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs b/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs deleted file mode 100644 index be3e58ba26..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/HttpKnownHeaderNames.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace Microsoft.AspNet.Security.Windows -{ - internal static class HttpKnownHeaderNames - { - public const string CacheControl = "Cache-Control"; - public const string Connection = "Connection"; - public const string Date = "Date"; - public const string KeepAlive = "Keep-Alive"; - public const string Pragma = "Pragma"; - public const string ProxyConnection = "Proxy-Connection"; - public const string Trailer = "Trailer"; - public const string TransferEncoding = "Transfer-Encoding"; - public const string Upgrade = "Upgrade"; - public const string Via = "Via"; - public const string Warning = "Warning"; - public const string ContentLength = "Content-Length"; - public const string ContentType = "Content-Type"; - public const string ContentDisposition = "Content-Disposition"; - public const string ContentEncoding = "Content-Encoding"; - public const string ContentLanguage = "Content-Language"; - public const string ContentLocation = "Content-Location"; - public const string ContentRange = "Content-Range"; - public const string Expires = "Expires"; - public const string LastModified = "Last-Modified"; - public const string Age = "Age"; - public const string Location = "Location"; - public const string ProxyAuthenticate = "Proxy-Authenticate"; - public const string RetryAfter = "Retry-After"; - public const string Server = "Server"; - public const string SetCookie = "Set-Cookie"; - public const string SetCookie2 = "Set-Cookie2"; - public const string Vary = "Vary"; - public const string WWWAuthenticate = "WWW-Authenticate"; - public const string Accept = "Accept"; - public const string AcceptCharset = "Accept-Charset"; - public const string AcceptEncoding = "Accept-Encoding"; - public const string AcceptLanguage = "Accept-Language"; - public const string Authorization = "Authorization"; - public const string Cookie = "Cookie"; - public const string Cookie2 = "Cookie2"; - public const string Expect = "Expect"; - public const string From = "From"; - public const string Host = "Host"; - public const string IfMatch = "If-Match"; - public const string IfModifiedSince = "If-Modified-Since"; - public const string IfNoneMatch = "If-None-Match"; - public const string IfRange = "If-Range"; - public const string IfUnmodifiedSince = "If-Unmodified-Since"; - public const string MaxForwards = "Max-Forwards"; - public const string ProxyAuthorization = "Proxy-Authorization"; - public const string Referer = "Referer"; - public const string Range = "Range"; - public const string UserAgent = "User-Agent"; - public const string ContentMD5 = "Content-MD5"; - public const string ETag = "ETag"; - public const string TE = "TE"; - public const string Allow = "Allow"; - public const string AcceptRanges = "Accept-Ranges"; - public const string P3P = "P3P"; - public const string XPoweredBy = "X-Powered-By"; - public const string XAspNetVersion = "X-AspNet-Version"; - public const string SecWebSocketKey = "Sec-WebSocket-Key"; - public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions"; - public const string SecWebSocketAccept = "Sec-WebSocket-Accept"; - public const string Origin = "Origin"; - public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol"; - public const string SecWebSocketVersion = "Sec-WebSocket-Version"; - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs b/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs deleted file mode 100644 index 8940131502..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/HttpStatusCode.cs +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.AspNet.Security.Windows -{ - // Redirect Status code numbers that need to be defined. - - /// - /// Contains the values of status - /// codes defined for the HTTP protocol. - /// - // UEUE : Any int can be cast to a HttpStatusCode to allow checking for non http1.1 codes. - internal enum HttpStatusCode - { - // Informational 1xx - - /// - /// [To be supplied.] - /// - Continue = 100, - - /// - /// [To be supplied.] - /// - SwitchingProtocols = 101, - - // Successful 2xx - - /// - /// [To be supplied.] - /// - OK = 200, - - /// - /// [To be supplied.] - /// - Created = 201, - - /// - /// [To be supplied.] - /// - Accepted = 202, - - /// - /// [To be supplied.] - /// - NonAuthoritativeInformation = 203, - - /// - /// [To be supplied.] - /// - NoContent = 204, - - /// - /// [To be supplied.] - /// - ResetContent = 205, - - /// - /// [To be supplied.] - /// - PartialContent = 206, - - // Redirection 3xx - - /// - /// [To be supplied.] - /// - MultipleChoices = 300, - - /// - /// [To be supplied.] - /// - Ambiguous = 300, - - /// - /// [To be supplied.] - /// - MovedPermanently = 301, - - /// - /// [To be supplied.] - /// - Moved = 301, - - /// - /// [To be supplied.] - /// - Found = 302, - - /// - /// [To be supplied.] - /// - Redirect = 302, - - /// - /// [To be supplied.] - /// - SeeOther = 303, - - /// - /// [To be supplied.] - /// - RedirectMethod = 303, - - /// - /// [To be supplied.] - /// - NotModified = 304, - - /// - /// [To be supplied.] - /// - UseProxy = 305, - - /// - /// [To be supplied.] - /// - Unused = 306, - - /// - /// [To be supplied.] - /// - TemporaryRedirect = 307, - - /// - /// [To be supplied.] - /// - RedirectKeepVerb = 307, - - // Client Error 4xx - - /// - /// [To be supplied.] - /// - BadRequest = 400, - - /// - /// [To be supplied.] - /// - Unauthorized = 401, - - /// - /// [To be supplied.] - /// - PaymentRequired = 402, - - /// - /// [To be supplied.] - /// - Forbidden = 403, - - /// - /// [To be supplied.] - /// - NotFound = 404, - - /// - /// [To be supplied.] - /// - MethodNotAllowed = 405, - - /// - /// [To be supplied.] - /// - NotAcceptable = 406, - - /// - /// [To be supplied.] - /// - ProxyAuthenticationRequired = 407, - - /// - /// [To be supplied.] - /// - RequestTimeout = 408, - - /// - /// [To be supplied.] - /// - Conflict = 409, - - /// - /// [To be supplied.] - /// - Gone = 410, - - /// - /// [To be supplied.] - /// - LengthRequired = 411, - - /// - /// [To be supplied.] - /// - PreconditionFailed = 412, - - /// - /// [To be supplied.] - /// - RequestEntityTooLarge = 413, - - /// - /// [To be supplied.] - /// - RequestUriTooLong = 414, - - /// - /// [To be supplied.] - /// - UnsupportedMediaType = 415, - - /// - /// [To be supplied.] - /// - RequestedRangeNotSatisfiable = 416, - - /// - /// [To be supplied.] - /// - ExpectationFailed = 417, - - UpgradeRequired = 426, - - // Server Error 5xx - - /// - /// [To be supplied.] - /// - InternalServerError = 500, - - /// - /// [To be supplied.] - /// - NotImplemented = 501, - - /// - /// [To be supplied.] - /// - BadGateway = 502, - - /// - /// [To be supplied.] - /// - ServiceUnavailable = 503, - - /// - /// [To be supplied.] - /// - GatewayTimeout = 504, - - /// - /// [To be supplied.] - /// - HttpVersionNotSupported = 505, - } // enum HttpStatusCode - -/* -Fielding, et al. Standards Track [Page 3] - -RFC 2616 HTTP/1.1 June 1999 - - - 10.1 Informational 1xx ...........................................57 - 10.1.1 100 Continue .............................................58 - 10.1.2 101 Switching Protocols ..................................58 - 10.2 Successful 2xx ..............................................58 - 10.2.1 200 OK ...................................................58 - 10.2.2 201 Created ..............................................59 - 10.2.3 202 Accepted .............................................59 - 10.2.4 203 Non-Authoritative Information ........................59 - 10.2.5 204 No Content ...........................................60 - 10.2.6 205 Reset Content ........................................60 - 10.2.7 206 Partial Content ......................................60 - 10.3 Redirection 3xx .............................................61 - 10.3.1 300 Multiple Choices .....................................61 - 10.3.2 301 Moved Permanently ....................................62 - 10.3.3 302 Found ................................................62 - 10.3.4 303 See Other ............................................63 - 10.3.5 304 Not Modified .........................................63 - 10.3.6 305 Use Proxy ............................................64 - 10.3.7 306 (Unused) .............................................64 - 10.3.8 307 Temporary Redirect ...................................65 - 10.4 Client Error 4xx ............................................65 - 10.4.1 400 Bad Request .........................................65 - 10.4.2 401 Unauthorized ........................................66 - 10.4.3 402 Payment Required ....................................66 - 10.4.4 403 Forbidden ...........................................66 - 10.4.5 404 Not Found ...........................................66 - 10.4.6 405 Method Not Allowed ..................................66 - 10.4.7 406 Not Acceptable ......................................67 - 10.4.8 407 Proxy Authentication Required .......................67 - 10.4.9 408 Request Timeout .....................................67 - 10.4.10 409 Conflict ............................................67 - 10.4.11 410 Gone ................................................68 - 10.4.12 411 Length Required .....................................68 - 10.4.13 412 Precondition Failed .................................68 - 10.4.14 413 Request Entity Too Large ............................69 - 10.4.15 414 Request-URI Too Long ................................69 - 10.4.16 415 Unsupported Media Type ..............................69 - 10.4.17 416 Requested Range Not Satisfiable .....................69 - 10.4.18 417 Expectation Failed ..................................70 - 10.5 Server Error 5xx ............................................70 - 10.5.1 500 Internal Server Error ................................70 - 10.5.2 501 Not Implemented ......................................70 - 10.5.3 502 Bad Gateway ..........................................70 - 10.5.4 503 Service Unavailable ..................................70 - 10.5.5 504 Gateway Timeout ......................................71 - 10.5.6 505 HTTP Version Not Supported ...........................71 -*/ -} // namespace System.Net diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs deleted file mode 100644 index 185bf0cb8b..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/CaseInsinsitiveAscii.cs +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System.Collections; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class CaseInsensitiveAscii : IEqualityComparer, IComparer - { - // ASCII char ToLower table - internal static readonly byte[] AsciiToLower = new byte[] - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, // 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, // 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, // 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255 - }; - - // ASCII string case insensitive hash function - public int GetHashCode(object myObject) - { - string myString = myObject as string; - if (myObject == null) - { - return 0; - } - int myHashCode = myString.Length; - if (myHashCode == 0) - { - return 0; - } - myHashCode ^= AsciiToLower[(byte)myString[0]] << 24 ^ AsciiToLower[(byte)myString[myHashCode - 1]] << 16; - return myHashCode; - } - - // ASCII string case insensitive comparer - public int Compare(object firstObject, object secondObject) - { - string firstString = firstObject as string; - string secondString = secondObject as string; - if (firstString == null) - { - return secondString == null ? 0 : -1; - } - if (secondString == null) - { - return 1; - } - int result = firstString.Length - secondString.Length; - int comparisons = result > 0 ? secondString.Length : firstString.Length; - int difference, index = 0; - while (index < comparisons) - { - difference = (int)(AsciiToLower[firstString[index]] - AsciiToLower[secondString[index]]); - if (difference != 0) - { - result = difference; - break; - } - index++; - } - return result; - } - - // ASCII string case insensitive hash function - private int FastGetHashCode(string myString) - { - int myHashCode = myString.Length; - if (myHashCode != 0) - { - myHashCode ^= AsciiToLower[(byte)myString[0]] << 24 ^ AsciiToLower[(byte)myString[myHashCode - 1]] << 16; - } - return myHashCode; - } - - // ASCII string case insensitive comparer - public new bool Equals(object firstObject, object secondObject) - { - string firstString = firstObject as string; - string secondString = secondObject as string; - if (firstString == null) - { - return secondString == null; - } - if (secondString != null) - { - int index = firstString.Length; - if (index == secondString.Length) - { - if (FastGetHashCode(firstString) == FastGetHashCode(secondString)) - { - int comparisons = firstString.Length; - while (index > 0) - { - index--; - if (AsciiToLower[firstString[index]] != AsciiToLower[secondString[index]]) - { - return false; - } - } - return true; - } - } - } - return false; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs deleted file mode 100644 index 38acdf476f..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/GlobalLog.cs +++ /dev/null @@ -1,706 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace Microsoft.AspNet.Security.Windows -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Configuration; - using System.Diagnostics; - using System.Globalization; - using System.Net; - using System.Runtime.ConstrainedExecution; - using System.Security.Permissions; - using System.Threading; - - /// - /// - /// - internal static class GlobalLog - { - // Logging Initalization - I need to disable Logging code, and limit - // the effect it has when it is dissabled, so I use a bool here. - // - // This can only be set when the logging code is built and enabled. - // By specifing the "CSC_DEFINES=/D:TRAVE" in the build environment, - // this code will be built and then checks against an enviroment variable - // and a BooleanSwitch to see if any of the two have enabled logging. - - private static BaseLoggingObject Logobject = GlobalLog.LoggingInitialize(); -#if TRAVE - internal static LocalDataStoreSlot s_ThreadIdSlot; - internal static bool s_UseThreadId; - internal static bool s_UseTimeSpan; - internal static bool s_DumpWebData; - internal static bool s_UsePerfCounter; - internal static bool s_DebugCallNesting; - internal static bool s_DumpToConsole; - internal static int s_MaxDumpSize; - internal static string s_RootDirectory; - - // - // Logging Config Variables - below are list of consts that can be used to config - // the logging, - // - - // Max number of lines written into a buffer, before a save is invoked - // s_DumpToConsole disables. - public const int MaxLinesBeforeSave = 0; - -#endif - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - private static BaseLoggingObject LoggingInitialize() - { -#if DEBUG - if (GetSwitchValue("SystemNetLogging", "System.Net logging module", false) && - GetSwitchValue("SystemNetLog_ConnectionMonitor", "System.Net connection monitor thread", false)) - { - InitConnectionMonitor(); - } -#endif // DEBUG -#if TRAVE - // by default we'll log to c:\temp\ so that non interactive services (like w3wp.exe) that don't have environment - // variables can easily be debugged, note that the ACLs of the directory might need to be adjusted - if (!GetSwitchValue("SystemNetLog_OverrideDefaults", "System.Net log override default settings", false)) { - s_ThreadIdSlot = Thread.AllocateDataSlot(); - s_UseThreadId = true; - s_UseTimeSpan = true; - s_DumpWebData = true; - s_MaxDumpSize = 256; - s_UsePerfCounter = true; - s_DebugCallNesting = true; - s_DumpToConsole = false; - s_RootDirectory = "C:\\Temp\\"; - return new LoggingObject(); - } - if (GetSwitchValue("SystemNetLogging", "System.Net logging module", false)) { - s_ThreadIdSlot = Thread.AllocateDataSlot(); - s_UseThreadId = GetSwitchValue("SystemNetLog_UseThreadId", "System.Net log display system thread id", false); - s_UseTimeSpan = GetSwitchValue("SystemNetLog_UseTimeSpan", "System.Net log display ticks as TimeSpan", false); - s_DumpWebData = GetSwitchValue("SystemNetLog_DumpWebData", "System.Net log display HTTP send/receive data", false); - s_MaxDumpSize = GetSwitchValue("SystemNetLog_MaxDumpSize", "System.Net log max size of display data", 256); - s_UsePerfCounter = GetSwitchValue("SystemNetLog_UsePerfCounter", "System.Net log use QueryPerformanceCounter() to get ticks ", false); - s_DebugCallNesting = GetSwitchValue("SystemNetLog_DebugCallNesting", "System.Net used to debug call nesting", false); - s_DumpToConsole = GetSwitchValue("SystemNetLog_DumpToConsole", "System.Net log to console", false); - s_RootDirectory = GetSwitchValue("SystemNetLog_RootDirectory", "System.Net root directory of log file", string.Empty); - return new LoggingObject(); - } -#endif // TRAVE - return new BaseLoggingObject(); - } - -#if TRAVE - private static string GetSwitchValue(string switchName, string switchDescription, string defaultValue) { - new EnvironmentPermission(PermissionState.Unrestricted).Assert(); - try { - defaultValue = Environment.GetEnvironmentVariable(switchName); - } - finally { - EnvironmentPermission.RevertAssert(); - } - return defaultValue; - } - - private static int GetSwitchValue(string switchName, string switchDescription, int defaultValue) { - IntegerSwitch theSwitch = new IntegerSwitch(switchName, switchDescription); - if (theSwitch.Enabled) { - return theSwitch.Value; - } - new EnvironmentPermission(PermissionState.Unrestricted).Assert(); - try { - string environmentVar = Environment.GetEnvironmentVariable(switchName); - if (environmentVar!=null) { - defaultValue = Int32.Parse(environmentVar.Trim(), CultureInfo.InvariantCulture); - } - } - finally { - EnvironmentPermission.RevertAssert(); - } - return defaultValue; - } - -#endif - -#if TRAVE || DEBUG - private static bool GetSwitchValue(string switchName, string switchDescription, bool defaultValue) - { - BooleanSwitch theSwitch = new BooleanSwitch(switchName, switchDescription); - new EnvironmentPermission(PermissionState.Unrestricted).Assert(); - try - { - if (theSwitch.Enabled) - { - return true; - } - string environmentVar = Environment.GetEnvironmentVariable(switchName); - defaultValue = environmentVar != null && environmentVar.Trim() == "1"; - } - catch (ConfigurationException) - { - } - finally - { - EnvironmentPermission.RevertAssert(); - } - return defaultValue; - } -#endif // TRAVE || DEBUG - - // Enables thread tracing, detects mis-use of threads. -#if DEBUG - [ThreadStatic] - private static Stack t_ThreadKindStack; - - private static Stack ThreadKindStack - { - get - { - if (t_ThreadKindStack == null) - { - t_ThreadKindStack = new Stack(); - } - return t_ThreadKindStack; - } - } -#endif - - internal static ThreadKinds CurrentThreadKind - { - get - { -#if DEBUG - return ThreadKindStack.Count > 0 ? ThreadKindStack.Peek() : ThreadKinds.Other; -#else - return ThreadKinds.Unknown; -#endif - } - } - - private static bool HasShutdownStarted - { - get - { - return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload(); - } - } - -#if DEBUG - // ifdef'd instead of conditional since people are forced to handle the return value. - // [Conditional("DEBUG")] - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - internal static IDisposable SetThreadKind(ThreadKinds kind) - { - if ((kind & ThreadKinds.SourceMask) != ThreadKinds.Unknown) - { - throw new InvalidOperationException(); - } - - // Ignore during shutdown. - if (HasShutdownStarted) - { - return null; - } - - ThreadKinds threadKind = CurrentThreadKind; - ThreadKinds source = threadKind & ThreadKinds.SourceMask; - -#if TRAVE - // Special warnings when doing dangerous things on a thread. - if ((threadKind & ThreadKinds.User) != 0 && (kind & ThreadKinds.System) != 0) - { - Print("WARNING: Thread changed from User to System; user's thread shouldn't be hijacked."); - } - - if ((threadKind & ThreadKinds.Async) != 0 && (kind & ThreadKinds.Sync) != 0) - { - Print("WARNING: Thread changed from Async to Sync, may block an Async thread."); - } - else if ((threadKind & (ThreadKinds.Other | ThreadKinds.CompletionPort)) == 0 && (kind & ThreadKinds.Sync) != 0) - { - Print("WARNING: Thread from a limited resource changed to Sync, may deadlock or bottleneck."); - } -#endif - - ThreadKindStack.Push( - (((kind & ThreadKinds.OwnerMask) == 0 ? threadKind : kind) & ThreadKinds.OwnerMask) | - (((kind & ThreadKinds.SyncMask) == 0 ? threadKind : kind) & ThreadKinds.SyncMask) | - (kind & ~(ThreadKinds.OwnerMask | ThreadKinds.SyncMask)) | - source); - -#if TRAVE - if (CurrentThreadKind != threadKind) - { - Print("Thread becomes:(" + CurrentThreadKind.ToString() + ")"); - } -#endif - - return new ThreadKindFrame(); - } - - private class ThreadKindFrame : IDisposable - { - private int m_FrameNumber; - - internal ThreadKindFrame() - { - m_FrameNumber = ThreadKindStack.Count; - } - - void IDisposable.Dispose() - { - // Ignore during shutdown. - if (GlobalLog.HasShutdownStarted) - { - return; - } - - if (m_FrameNumber != ThreadKindStack.Count) - { - throw new InvalidOperationException(); - } - - ThreadKinds previous = ThreadKindStack.Pop(); - -#if TRAVE - if (CurrentThreadKind != previous) - { - Print("Thread reverts:(" + CurrentThreadKind.ToString() + ")"); - } -#endif - } - } -#endif - - [Conditional("DEBUG")] - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - internal static void SetThreadSource(ThreadKinds source) - { -#if DEBUG - if ((source & ThreadKinds.SourceMask) != source || source == ThreadKinds.Unknown) - { - throw new ArgumentException("Must specify the thread source.", "source"); - } - - if (ThreadKindStack.Count == 0) - { - ThreadKindStack.Push(source); - return; - } - - if (ThreadKindStack.Count > 1) - { - Print("WARNING: SetThreadSource must be called at the base of the stack, or the stack has been corrupted."); - while (ThreadKindStack.Count > 1) - { - ThreadKindStack.Pop(); - } - } - - if (ThreadKindStack.Peek() != source) - { - // SQL can fail to clean up the stack, leaving the default Other at the bottom. Replace it. - Print("WARNING: The stack has been corrupted."); - ThreadKinds last = ThreadKindStack.Pop() & ThreadKinds.SourceMask; - Assert(last == source || last == ThreadKinds.Other, "Thread source changed.|Was:({0}) Now:({1})", last, source); - ThreadKindStack.Push(source); - } -#endif - } - - [Conditional("DEBUG")] - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - internal static void ThreadContract(ThreadKinds kind, string errorMsg) - { - ThreadContract(kind, ThreadKinds.SafeSources, errorMsg); - } - - [Conditional("DEBUG")] - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - internal static void ThreadContract(ThreadKinds kind, ThreadKinds allowedSources, string errorMsg) - { - if ((kind & ThreadKinds.SourceMask) != ThreadKinds.Unknown || (allowedSources & ThreadKinds.SourceMask) != allowedSources) - { - throw new InvalidOperationException(); - } - - ThreadKinds threadKind = CurrentThreadKind; - Assert((threadKind & allowedSources) != 0, errorMsg, "Thread Contract Violation.|Expected source:({0}) Actual source:({1})", allowedSources, threadKind & ThreadKinds.SourceMask); - Assert((threadKind & kind) == kind, errorMsg, "Thread Contract Violation.|Expected kind:({0}) Actual kind:({1})", kind, threadKind & ~ThreadKinds.SourceMask); - } - -#if DEBUG - // Enables auto-hang detection, which will "snap" a log on hang - internal static bool EnableMonitorThread = false; - - // Default value for hang timer -#if FEATURE_PAL // ROTORTODO - after speedups (like real JIT and GC) remove this - public const int DefaultTickValue = 1000*60*5; // 5 minutes -#else - public const int DefaultTickValue = 1000 * 60; // 60 secs -#endif // FEATURE_PAL -#endif // DEBUG - - [System.Diagnostics.Conditional("TRAVE")] - public static void AddToArray(string msg) - { -#if TRAVE - GlobalLog.Logobject.PrintLine(msg); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Ignore(object msg) - { - } - - [System.Diagnostics.Conditional("TRAVE")] - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - public static void Print(string msg) - { -#if TRAVE - GlobalLog.Logobject.PrintLine(msg); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void PrintHex(string msg, object value) - { -#if TRAVE - GlobalLog.Logobject.PrintLine(msg+TraveHelper.ToHex(value)); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Enter(string func) - { -#if TRAVE - GlobalLog.Logobject.EnterFunc(func + "(*none*)"); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Enter(string func, string parms) - { -#if TRAVE - GlobalLog.Logobject.EnterFunc(func + "(" + parms + ")"); -#endif - } - - [Conditional("DEBUG")] - [Conditional("_FORCE_ASSERTS")] - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - public static void Assert(bool condition, string messageFormat, params object[] data) - { - if (!condition) - { - string fullMessage = string.Format(CultureInfo.InvariantCulture, messageFormat, data); - int pipeIndex = fullMessage.IndexOf('|'); - if (pipeIndex == -1) - { - Assert(fullMessage); - } - else - { - int detailLength = fullMessage.Length - pipeIndex - 1; - Assert(fullMessage.Substring(0, pipeIndex), detailLength > 0 ? fullMessage.Substring(pipeIndex + 1, detailLength) : null); - } - } - } - - [Conditional("DEBUG")] - [Conditional("_FORCE_ASSERTS")] - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - public static void Assert(string message) - { - Assert(message, null); - } - - [Conditional("DEBUG")] - [Conditional("_FORCE_ASSERTS")] - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - public static void Assert(string message, string detailMessage) - { - try - { - Print("Assert: " + message + (!string.IsNullOrEmpty(detailMessage) ? ": " + detailMessage : string.Empty)); - Print("*******"); - Logobject.DumpArray(false); - } - finally - { -#if DEBUG && !STRESS - Debug.Assert(false, message, detailMessage); -#endif - } - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void LeaveException(string func, Exception exception) - { -#if TRAVE - GlobalLog.Logobject.LeaveFunc(func + " exception " + ((exception!=null) ? exception.Message : String.Empty)); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Leave(string func) - { -#if TRAVE - GlobalLog.Logobject.LeaveFunc(func + " returns "); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Leave(string func, string result) - { -#if TRAVE - GlobalLog.Logobject.LeaveFunc(func + " returns " + result); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Leave(string func, int returnval) - { -#if TRAVE - GlobalLog.Logobject.LeaveFunc(func + " returns " + returnval.ToString()); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Leave(string func, bool returnval) - { -#if TRAVE - GlobalLog.Logobject.LeaveFunc(func + " returns " + returnval.ToString()); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void DumpArray() - { -#if TRAVE - GlobalLog.Logobject.DumpArray(true); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Dump(byte[] buffer) - { -#if TRAVE - Logobject.Dump(buffer, 0, buffer!=null ? buffer.Length : -1); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Dump(byte[] buffer, int length) - { -#if TRAVE - Logobject.Dump(buffer, 0, length); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Dump(byte[] buffer, int offset, int length) - { -#if TRAVE - Logobject.Dump(buffer, offset, length); -#endif - } - - [System.Diagnostics.Conditional("TRAVE")] - public static void Dump(IntPtr buffer, int offset, int length) - { -#if TRAVE - Logobject.Dump(buffer, offset, length); -#endif - } - -#if DEBUG - private class HttpWebRequestComparer : IComparer - { - public int Compare( - object x1, - object y1) - { - HttpWebRequest x = (HttpWebRequest)x1; - HttpWebRequest y = (HttpWebRequest)y1; - - if (x.GetHashCode() == y.GetHashCode()) - { - return 0; - } - else if (x.GetHashCode() < y.GetHashCode()) - { - return -1; - } - else if (x.GetHashCode() > y.GetHashCode()) - { - return 1; - } - - return 0; - } - } - /* - private class ConnectionMonitorEntry { - public HttpWebRequest m_Request; - public int m_Flags; - public DateTime m_TimeAdded; - public Connection m_Connection; - - public ConnectionMonitorEntry(HttpWebRequest request, Connection connection, int flags) { - m_Request = request; - m_Connection = connection; - m_Flags = flags; - m_TimeAdded = DateTime.Now; - } - } - */ - private static volatile ManualResetEvent s_ShutdownEvent; - private static volatile SortedList s_RequestList; - - internal const int WaitingForReadDoneFlag = 0x1; -#endif - /* -#if DEBUG - private static void ConnectionMonitor() { - while(! s_ShutdownEvent.WaitOne(DefaultTickValue, false)) { - if (GlobalLog.EnableMonitorThread) { -#if TRAVE - GlobalLog.Logobject.LoggingMonitorTick(); -#endif - } - - int hungCount = 0; - lock (s_RequestList) { - DateTime dateNow = DateTime.Now; - DateTime dateExpired = dateNow.AddSeconds(-DefaultTickValue); - foreach (ConnectionMonitorEntry monitorEntry in s_RequestList.GetValueList() ) { - if (monitorEntry != null && - (dateExpired > monitorEntry.m_TimeAdded)) - { - hungCount++; -#if TRAVE - GlobalLog.Print("delay:" + (dateNow - monitorEntry.m_TimeAdded).TotalSeconds + - " req#" + monitorEntry.m_Request.GetHashCode() + - " cnt#" + monitorEntry.m_Connection.GetHashCode() + - " flags:" + monitorEntry.m_Flags); - -#endif - monitorEntry.m_Connection.Debug(monitorEntry.m_Request.GetHashCode()); - } - } - } - Assert(hungCount == 0, "Warning: Hang Detected on Connection(s) of greater than {0} ms. {1} request(s) hung.|Please Dump System.Net.GlobalLog.s_RequestList for pending requests, make sure your streams are calling Close(), and that your destination server is up.", DefaultTickValue, hungCount); - } - } -#endif // DEBUG - **/ -#if DEBUG - [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)] - internal static void AppDomainUnloadEvent(object sender, EventArgs e) - { - s_ShutdownEvent.Set(); - } -#endif - -#if DEBUG - [System.Diagnostics.Conditional("DEBUG")] - private static void InitConnectionMonitor() - { - s_RequestList = new SortedList(new HttpWebRequestComparer(), 10); - s_ShutdownEvent = new ManualResetEvent(false); - AppDomain.CurrentDomain.DomainUnload += new EventHandler(AppDomainUnloadEvent); - AppDomain.CurrentDomain.ProcessExit += new EventHandler(AppDomainUnloadEvent); - // Thread threadMonitor = new Thread(new ThreadStart(ConnectionMonitor)); - // threadMonitor.IsBackground = true; - // threadMonitor.Start(); - } -#endif - /* - [System.Diagnostics.Conditional("DEBUG")] - internal static void DebugAddRequest(HttpWebRequest request, Connection connection, int flags) { -#if DEBUG - // null if the connection monitor is off - if(s_RequestList == null) - return; - - lock(s_RequestList) { - Assert(!s_RequestList.ContainsKey(request), "s_RequestList.ContainsKey(request)|A HttpWebRequest should not be submitted twice."); - - ConnectionMonitorEntry requestEntry = - new ConnectionMonitorEntry(request, connection, flags); - - try { - s_RequestList.Add(request, requestEntry); - } catch { - } - } -#endif - } -*/ - /* - [System.Diagnostics.Conditional("DEBUG")] - internal static void DebugRemoveRequest(HttpWebRequest request) { - #if DEBUG - // null if the connection monitor is off - if(s_RequestList == null) - return; - - lock(s_RequestList) { - Assert(s_RequestList.ContainsKey(request), "!s_RequestList.ContainsKey(request)|A HttpWebRequest should not be removed twice."); - - try { - s_RequestList.Remove(request); - } catch { - } - } - #endif - } - */ - /* - [System.Diagnostics.Conditional("DEBUG")] - internal static void DebugUpdateRequest(HttpWebRequest request, Connection connection, int flags) { -#if DEBUG - // null if the connection monitor is off - if(s_RequestList == null) - return; - - lock(s_RequestList) { - if(!s_RequestList.ContainsKey(request)) { - return; - } - - ConnectionMonitorEntry requestEntry = - new ConnectionMonitorEntry(request, connection, flags); - - try { - s_RequestList.Remove(request); - s_RequestList.Add(request, requestEntry); - } catch { - } - } -#endif - }*/ - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs deleted file mode 100644 index fc8d821adb..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/HttpListenerContext.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Security.Principal; - -namespace Microsoft.AspNet.Security.Windows -{ - // TODO: At what point does a user need to be cleaned up? - internal sealed class HttpListenerContext - { - private WindowsAuthMiddleware _winAuth; - private IPrincipal _user = null; - - internal const string NTLM = "NTLM"; - - internal HttpListenerContext(WindowsAuthMiddleware httpListener) - { - _winAuth = httpListener; - } - - internal void Close() - { - if (Logging.On) - { - Logging.Enter(Logging.HttpListener, this, "Close()", string.Empty); - } - - IDisposable user = _user == null ? null : _user.Identity as IDisposable; - - // TODO: At what point does a user need to be cleaned up? - - // For unsafe connection ntlm auth we dont dispose this identity as yet since its cached - if ((user != null) && - (_user.Identity.AuthenticationType != NTLM) && - (!_winAuth.UnsafeConnectionNtlmAuthentication)) - { - user.Dispose(); - } - if (Logging.On) - { - Logging.Exit(Logging.HttpListener, this, "Close", string.Empty); - } - } - - internal void Abort() - { - if (Logging.On) - { - Logging.Enter(Logging.HttpListener, this, "Abort", string.Empty); - } - - IDisposable user = _user == null ? null : _user.Identity as IDisposable; - if (user != null) - { - user.Dispose(); - } - if (Logging.On) - { - Logging.Exit(Logging.HttpListener, this, "Abort", string.Empty); - } - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs deleted file mode 100644 index a7f83f210c..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/Internal.cs +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Net.Security; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; -using System.Security.Authentication.ExtendedProtection; -using System.Security.Cryptography.X509Certificates; -using System.Security.Permissions; - -namespace Microsoft.AspNet.Security.Windows -{ - internal enum SecurityStatus - { - // Success / Informational - OK = 0x00000000, - ContinueNeeded = unchecked((int)0x00090312), - CompleteNeeded = unchecked((int)0x00090313), - CompAndContinue = unchecked((int)0x00090314), - ContextExpired = unchecked((int)0x00090317), - CredentialsNeeded = unchecked((int)0x00090320), - Renegotiate = unchecked((int)0x00090321), - - // Errors - OutOfMemory = unchecked((int)0x80090300), - InvalidHandle = unchecked((int)0x80090301), - Unsupported = unchecked((int)0x80090302), - TargetUnknown = unchecked((int)0x80090303), - InternalError = unchecked((int)0x80090304), - PackageNotFound = unchecked((int)0x80090305), - NotOwner = unchecked((int)0x80090306), - CannotInstall = unchecked((int)0x80090307), - InvalidToken = unchecked((int)0x80090308), - CannotPack = unchecked((int)0x80090309), - QopNotSupported = unchecked((int)0x8009030A), - NoImpersonation = unchecked((int)0x8009030B), - LogonDenied = unchecked((int)0x8009030C), - UnknownCredentials = unchecked((int)0x8009030D), - NoCredentials = unchecked((int)0x8009030E), - MessageAltered = unchecked((int)0x8009030F), - OutOfSequence = unchecked((int)0x80090310), - NoAuthenticatingAuthority = unchecked((int)0x80090311), - IncompleteMessage = unchecked((int)0x80090318), - IncompleteCredentials = unchecked((int)0x80090320), - BufferNotEnough = unchecked((int)0x80090321), - WrongPrincipal = unchecked((int)0x80090322), - TimeSkew = unchecked((int)0x80090324), - UntrustedRoot = unchecked((int)0x80090325), - IllegalMessage = unchecked((int)0x80090326), - CertUnknown = unchecked((int)0x80090327), - CertExpired = unchecked((int)0x80090328), - AlgorithmMismatch = unchecked((int)0x80090331), - SecurityQosFailed = unchecked((int)0x80090332), - SmartcardLogonRequired = unchecked((int)0x8009033E), - UnsupportedPreauth = unchecked((int)0x80090343), - BadBinding = unchecked((int)0x80090346) - } - - internal enum ContextAttribute - { - // look into and - Sizes = 0x00, - Names = 0x01, - Lifespan = 0x02, - DceInfo = 0x03, - StreamSizes = 0x04, - // KeyInfo = 0x05, must not be used, see ConnectionInfo instead - Authority = 0x06, - // SECPKG_ATTR_PROTO_INFO = 7, - // SECPKG_ATTR_PASSWORD_EXPIRY = 8, - // SECPKG_ATTR_SESSION_KEY = 9, - PackageInfo = 0x0A, - // SECPKG_ATTR_USER_FLAGS = 11, - NegotiationInfo = 0x0C, - // SECPKG_ATTR_NATIVE_NAMES = 13, - // SECPKG_ATTR_FLAGS = 14, - // SECPKG_ATTR_USE_VALIDATED = 15, - // SECPKG_ATTR_CREDENTIAL_NAME = 16, - // SECPKG_ATTR_TARGET_INFORMATION = 17, - // SECPKG_ATTR_ACCESS_TOKEN = 18, - // SECPKG_ATTR_TARGET = 19, - // SECPKG_ATTR_AUTHENTICATION_ID = 20, - UniqueBindings = 0x19, - EndpointBindings = 0x1A, - ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27 - RemoteCertificate = 0x53, - LocalCertificate = 0x54, - RootStore = 0x55, - IssuerListInfoEx = 0x59, - ConnectionInfo = 0x5A, - // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock - // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr - // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo - // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData - // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates - // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy - // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult - // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group - // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo - // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo - // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo - // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures - // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT - UiInfo = 0x68, // sets SEcPkgContext_UiInfo - } - - internal enum Endianness - { - Network = 0x00, - Native = 0x10, - } - - internal enum CredentialUse - { - Inbound = 0x1, - Outbound = 0x2, - Both = 0x3, - } - - internal enum BufferType - { - Empty = 0x00, - Data = 0x01, - Token = 0x02, - Parameters = 0x03, - Missing = 0x04, - Extra = 0x05, - Trailer = 0x06, - Header = 0x07, - Padding = 0x09, // non-data padding - Stream = 0x0A, - ChannelBindings = 0x0E, - TargetHost = 0x10, - ReadOnlyFlag = unchecked((int)0x80000000), - ReadOnlyWithChecksum = 0x10000000 - } - - // SecPkgContext_IssuerListInfoEx - [StructLayout(LayoutKind.Sequential)] - internal struct IssuerListInfoEx - { - public SafeHandle aIssuers; - public uint cIssuers; - - public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) - { - aIssuers = handle; - fixed (byte* voidPtr = nativeBuffer) - { - // if this breaks on 64 bit, do the sizeof(IntPtr) trick - cIssuers = *((uint*)(voidPtr + IntPtr.Size)); - } - } - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SecureCredential - { - /* - typedef struct _SCHANNEL_CRED - { - DWORD dwVersion; // always SCHANNEL_CRED_VERSION - DWORD cCreds; - PCCERT_CONTEXT *paCred; - HCERTSTORE hRootStore; - - DWORD cMappers; - struct _HMAPPER **aphMappers; - - DWORD cSupportedAlgs; - ALG_ID * palgSupportedAlgs; - - DWORD grbitEnabledProtocols; - DWORD dwMinimumCipherStrength; - DWORD dwMaximumCipherStrength; - DWORD dwSessionLifespan; - DWORD dwFlags; - DWORD reserved; - } SCHANNEL_CRED, *PSCHANNEL_CRED; - */ - - public const int CurrentVersion = 0x4; - - public int version; - public int cCreds; - - // ptr to an array of pointers - // There is a hack done with this field. AcquireCredentialsHandle requires an array of - // certificate handles; we only ever use one. In order to avoid pinning a one element array, - // we copy this value onto the stack, create a pointer on the stack to the copied value, - // and replace this field with the pointer, during the call to AcquireCredentialsHandle. - // Then we fix it up afterwards. Fine as long as all the SSPI credentials are not - // supposed to be threadsafe. - public IntPtr certContextArray; - - private readonly IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE - public int cMappers; - private readonly IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE - public int cSupportedAlgs; - private readonly IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE - public SchProtocols grbitEnabledProtocols; - public int dwMinimumCipherStrength; - public int dwMaximumCipherStrength; - public int dwSessionLifespan; - public SecureCredential.Flags dwFlags; - public int reserved; - - public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) - { - // default values required for a struct - rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero; - cCreds = cMappers = cSupportedAlgs = 0; - - if (policy == EncryptionPolicy.RequireEncryption) - { - // Prohibit null encryption cipher - dwMinimumCipherStrength = 0; - dwMaximumCipherStrength = 0; - } - else if (policy == EncryptionPolicy.AllowNoEncryption) - { - // Allow null encryption cipher in addition to other ciphers - dwMinimumCipherStrength = -1; - dwMaximumCipherStrength = 0; - } - else if (policy == EncryptionPolicy.NoEncryption) - { - // Suppress all encryption and require null encryption cipher only - dwMinimumCipherStrength = -1; - dwMaximumCipherStrength = -1; - } - else - { - throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy"); - } - - dwSessionLifespan = reserved = 0; - this.version = version; - dwFlags = flags; - grbitEnabledProtocols = protocols; - if (certificate != null) - { - certContextArray = certificate.Handle; - cCreds = 1; - } - } - - [Flags] - public enum Flags - { - Zero = 0, - NoSystemMapper = 0x02, - NoNameCheck = 0x04, - ValidateManual = 0x08, - NoDefaultCred = 0x10, - ValidateAuto = 0x20 - } - } // SecureCredential - - [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable", - Justification = "This structure does not own the native resource.")] - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct SecurityBufferStruct - { - public int count; - public BufferType type; - public IntPtr token; - - public static readonly int Size = sizeof(SecurityBufferStruct); - } - - internal static class IntPtrHelper - { - internal static IntPtr Add(IntPtr a, int b) - { - return (IntPtr)((long)a + (long)b); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs deleted file mode 100644 index 47dcb0c978..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/Logging.cs +++ /dev/null @@ -1,674 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Security; -using System.Threading; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class Logging - { - private const string AttributeNameMaxSize = "maxdatasize"; - private const string AttributeNameTraceMode = "tracemode"; - private const string AttributeValueProtocolOnly = "protocolonly"; - // private const string AttributeValueIncludeHex = "includehex"; - - private const int DefaultMaxDumpSize = 1024; - private const bool DefaultUseProtocolTextOnly = false; - - private const string TraceSourceWebName = "System.Net"; - private const string TraceSourceHttpListenerName = "System.Net.HttpListener"; - - private static readonly string[] SupportedAttributes = new string[] { AttributeNameMaxSize, AttributeNameTraceMode }; - - private static volatile bool s_LoggingEnabled = true; - private static volatile bool s_LoggingInitialized; - private static volatile bool s_AppDomainShutdown; - - private static TraceSource s_WebTraceSource; - private static TraceSource s_HttpListenerTraceSource; - - private static object s_InternalSyncObject; - - private Logging() - { - } - - private static object InternalSyncObject - { - get - { - if (s_InternalSyncObject == null) - { - object o = new Object(); - Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); - } - return s_InternalSyncObject; - } - } - - internal static bool On - { - get - { - if (!s_LoggingInitialized) - { - InitializeLogging(); - } - return s_LoggingEnabled; - } - } - - internal static bool IsVerbose(TraceSource traceSource) - { - return ValidateSettings(traceSource, TraceEventType.Verbose); - } - - internal static TraceSource Web - { - get - { - if (!s_LoggingInitialized) - { - InitializeLogging(); - } - if (!s_LoggingEnabled) - { - return null; - } - return s_WebTraceSource; - } - } - - internal static TraceSource HttpListener - { - get - { - if (!s_LoggingInitialized) - { - InitializeLogging(); - } - if (!s_LoggingEnabled) - { - return null; - } - return s_HttpListenerTraceSource; - } - } - - private static bool GetUseProtocolTextSetting(TraceSource traceSource) - { - bool useProtocolTextOnly = DefaultUseProtocolTextOnly; - if (traceSource.Attributes[AttributeNameTraceMode] == AttributeValueProtocolOnly) - { - useProtocolTextOnly = true; - } - return useProtocolTextOnly; - } - - private static int GetMaxDumpSizeSetting(TraceSource traceSource) - { - int maxDumpSize = DefaultMaxDumpSize; - if (traceSource.Attributes.ContainsKey(AttributeNameMaxSize)) - { - try - { - maxDumpSize = Int32.Parse(traceSource.Attributes[AttributeNameMaxSize], NumberFormatInfo.InvariantInfo); - } - catch (Exception exception) - { - if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) - { - throw; - } - traceSource.Attributes[AttributeNameMaxSize] = maxDumpSize.ToString(NumberFormatInfo.InvariantInfo); - } - } - return maxDumpSize; - } - - /// - /// Sets up internal config settings for logging. (MUST be called under critsec) - /// - private static void InitializeLogging() - { - lock (InternalSyncObject) - { - if (!s_LoggingInitialized) - { - bool loggingEnabled = false; - s_WebTraceSource = new NclTraceSource(TraceSourceWebName); - s_HttpListenerTraceSource = new NclTraceSource(TraceSourceHttpListenerName); - - GlobalLog.Print("Initalizating tracing"); - - try - { - loggingEnabled = (s_WebTraceSource.Switch.ShouldTrace(TraceEventType.Critical) || - s_HttpListenerTraceSource.Switch.ShouldTrace(TraceEventType.Critical)); - } - catch (SecurityException) - { - // These may throw if the caller does not have permission to hook up trace listeners. - // We treat this case as though logging were disabled. - Close(); - loggingEnabled = false; - } - if (loggingEnabled) - { - AppDomain currentDomain = AppDomain.CurrentDomain; - currentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler); - currentDomain.DomainUnload += new EventHandler(AppDomainUnloadEvent); - currentDomain.ProcessExit += new EventHandler(ProcessExitEvent); - } - s_LoggingEnabled = loggingEnabled; - s_LoggingInitialized = true; - } - } - } - - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Logging functions must work in partial trust mode")] - private static void Close() - { - if (s_WebTraceSource != null) - { - s_WebTraceSource.Close(); - } - if (s_HttpListenerTraceSource != null) - { - s_HttpListenerTraceSource.Close(); - } - } - - /// - /// Logs any unhandled exception through this event handler - /// - private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) - { - Exception e = (Exception)args.ExceptionObject; - Exception(Web, sender, "UnhandledExceptionHandler", e); - } - - private static void ProcessExitEvent(object sender, EventArgs e) - { - Close(); - s_AppDomainShutdown = true; - } - - /// - /// Called when the system is shutting down, used to prevent additional logging post-shutdown - /// - private static void AppDomainUnloadEvent(object sender, EventArgs e) - { - Close(); - s_AppDomainShutdown = true; - } - - /// - /// Confirms logging is enabled, given current logging settings - /// - private static bool ValidateSettings(TraceSource traceSource, TraceEventType traceLevel) - { - if (!s_LoggingEnabled) - { - return false; - } - if (!s_LoggingInitialized) - { - InitializeLogging(); - } - if (traceSource == null || !traceSource.Switch.ShouldTrace(traceLevel)) - { - return false; - } - if (s_AppDomainShutdown) - { - return false; - } - return true; - } - - /// - /// Converts an object to a normalized string that can be printed - /// takes System.Net.ObjectNamedFoo and coverts to ObjectNamedFoo, - /// except IPAddress, IPEndPoint, and Uri, which return ToString() - /// - /// - private static string GetObjectName(object obj) - { - if (obj is Uri || obj is System.Net.IPAddress || obj is System.Net.IPEndPoint) - { - return obj.ToString(); - } - else - { - return obj.GetType().Name; - } - } - - internal static uint GetThreadId() - { - uint threadId = UnsafeNclNativeMethods.GetCurrentThreadId(); - if (threadId == 0) - { - threadId = (uint)Thread.CurrentThread.GetHashCode(); - } - return threadId; - } - - internal static void PrintLine(TraceSource traceSource, TraceEventType eventType, int id, string msg) - { - string logHeader = "[" + GetThreadId().ToString("d4", CultureInfo.InvariantCulture) + "] "; - traceSource.TraceEvent(eventType, id, logHeader + msg); - } - - /// - /// Indicates that two objects are getting used with one another - /// - internal static void Associate(TraceSource traceSource, object objA, object objB) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - - string lineA = GetObjectName(objA) + "#" + ValidationHelper.HashString(objA); - string lineB = GetObjectName(objB) + "#" + ValidationHelper.HashString(objB); - - PrintLine(traceSource, TraceEventType.Information, 0, "Associating " + lineA + " with " + lineB); - } - - /// - /// Logs entrance to a function - /// - internal static void Enter(TraceSource traceSource, object obj, string method, string param) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - Enter(traceSource, GetObjectName(obj) + "#" + ValidationHelper.HashString(obj), method, param); - } - - /// - /// Logs entrance to a function - /// - internal static void Enter(TraceSource traceSource, object obj, string method, object paramObject) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - Enter(traceSource, GetObjectName(obj) + "#" + ValidationHelper.HashString(obj), method, paramObject); - } - - /// - /// Logs entrance to a function - /// - internal static void Enter(TraceSource traceSource, string obj, string method, string param) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - Enter(traceSource, obj + "::" + method + "(" + param + ")"); - } - - /// - /// Logs entrance to a function - /// - internal static void Enter(TraceSource traceSource, string obj, string method, object paramObject) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - string paramObjectValue = string.Empty; - if (paramObject != null) - { - paramObjectValue = GetObjectName(paramObject) + "#" + ValidationHelper.HashString(paramObject); - } - Enter(traceSource, obj + "::" + method + "(" + paramObjectValue + ")"); - } - - /// - /// Logs entrance to a function, indents and points that out - /// - internal static void Enter(TraceSource traceSource, string method, string parameters) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - Enter(traceSource, method + "(" + parameters + ")"); - } - - /// - /// Logs entrance to a function, indents and points that out - /// - internal static void Enter(TraceSource traceSource, string msg) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - // Trace.CorrelationManager.StartLogicalOperation(); - PrintLine(traceSource, TraceEventType.Verbose, 0, msg); - } - - /// - /// Logs exit from a function - /// - internal static void Exit(TraceSource traceSource, object obj, string method, object retObject) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - string retValue = string.Empty; - if (retObject != null) - { - retValue = GetObjectName(retObject) + "#" + ValidationHelper.HashString(retObject); - } - Exit(traceSource, obj, method, retValue); - } - - /// - /// Logs exit from a function - /// - internal static void Exit(TraceSource traceSource, string obj, string method, object retObject) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - string retValue = string.Empty; - if (retObject != null) - { - retValue = GetObjectName(retObject) + "#" + ValidationHelper.HashString(retObject); - } - Exit(traceSource, obj, method, retValue); - } - - /// - /// Logs exit from a function - /// - internal static void Exit(TraceSource traceSource, object obj, string method, string retValue) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - Exit(traceSource, GetObjectName(obj) + "#" + ValidationHelper.HashString(obj), method, retValue); - } - - /// - /// Logs exit from a function - /// - internal static void Exit(TraceSource traceSource, string obj, string method, string retValue) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - if (!string.IsNullOrEmpty(retValue)) - { - retValue = "\t-> " + retValue; - } - Exit(traceSource, obj + "::" + method + "() " + retValue); - } - - /// - /// Logs exit from a function - /// - internal static void Exit(TraceSource traceSource, string method, string parameters) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - Exit(traceSource, method + "() " + parameters); - } - - /// - /// Logs exit from a function - /// - internal static void Exit(TraceSource traceSource, string msg) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - PrintLine(traceSource, TraceEventType.Verbose, 0, "Exiting " + msg); - // Trace.CorrelationManager.StopLogicalOperation(); - } - - /// - /// Logs Exception, restores indenting - /// - internal static void Exception(TraceSource traceSource, object obj, string method, Exception e) - { - if (!ValidateSettings(traceSource, TraceEventType.Error)) - { - return; - } - - string infoLine = SR.GetString(SR.net_log_exception, GetObjectLogHash(obj), method, e.Message); - if (!string.IsNullOrEmpty(e.StackTrace)) - { - infoLine += "\r\n" + e.StackTrace; - } - PrintLine(traceSource, TraceEventType.Error, 0, infoLine); - } - - /// - /// Logs an Info line - /// - internal static void PrintInfo(TraceSource traceSource, string msg) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - PrintLine(traceSource, TraceEventType.Information, 0, msg); - } - - /// - /// Logs an Info line - /// - internal static void PrintInfo(TraceSource traceSource, object obj, string msg) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - PrintLine(traceSource, TraceEventType.Information, 0, - GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) - + " - " + msg); - } - - /// - /// Logs an Info line - /// - internal static void PrintInfo(TraceSource traceSource, object obj, string method, string param) - { - if (!ValidateSettings(traceSource, TraceEventType.Information)) - { - return; - } - PrintLine(traceSource, TraceEventType.Information, 0, - GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) - + "::" + method + "(" + param + ")"); - } - - /// - /// Logs a Warning line - /// - internal static void PrintWarning(TraceSource traceSource, string msg) - { - if (!ValidateSettings(traceSource, TraceEventType.Warning)) - { - return; - } - PrintLine(traceSource, TraceEventType.Warning, 0, msg); - } - - /// - /// Logs a Warning line - /// - internal static void PrintWarning(TraceSource traceSource, object obj, string method, string msg) - { - if (!ValidateSettings(traceSource, TraceEventType.Warning)) - { - return; - } - PrintLine(traceSource, TraceEventType.Warning, 0, - GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) - + "::" + method + "() - " + msg); - } - - /// - /// Logs an Error line - /// - internal static void PrintError(TraceSource traceSource, string msg) - { - if (!ValidateSettings(traceSource, TraceEventType.Error)) - { - return; - } - PrintLine(traceSource, TraceEventType.Error, 0, msg); - } - - /// - /// Logs an Error line - /// - internal static void PrintError(TraceSource traceSource, object obj, string method, string msg) - { - if (!ValidateSettings(traceSource, TraceEventType.Error)) - { - return; - } - PrintLine(traceSource, TraceEventType.Error, 0, - GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) - + "::" + method + "() - " + msg); - } - - internal static string GetObjectLogHash(object obj) - { - return GetObjectName(obj) + "#" + ValidationHelper.HashString(obj); - } - - /// - /// Marhsalls a buffer ptr to an array and then dumps the byte array to the log - /// - internal static void Dump(TraceSource traceSource, object obj, string method, IntPtr bufferPtr, int length) - { - if (!ValidateSettings(traceSource, TraceEventType.Verbose) || bufferPtr == IntPtr.Zero || length < 0) - { - return; - } - byte[] buffer = new byte[length]; - Marshal.Copy(bufferPtr, buffer, 0, length); - Dump(traceSource, obj, method, buffer, 0, length); - } - - /// - /// Dumps a byte array to the log - /// - internal static void Dump(TraceSource traceSource, object obj, string method, byte[] buffer, int offset, int length) - { - if (!ValidateSettings(traceSource, TraceEventType.Verbose)) - { - return; - } - if (buffer == null) - { - PrintLine(traceSource, TraceEventType.Verbose, 0, "(null)"); - return; - } - if (offset > buffer.Length) - { - PrintLine(traceSource, TraceEventType.Verbose, 0, "(offset out of range)"); - return; - } - PrintLine(traceSource, TraceEventType.Verbose, 0, "Data from " + GetObjectName(obj) + "#" + ValidationHelper.HashString(obj) + "::" + method); - int maxDumpSize = GetMaxDumpSizeSetting(traceSource); - if (length > maxDumpSize) - { - PrintLine(traceSource, TraceEventType.Verbose, 0, "(printing " + maxDumpSize.ToString(NumberFormatInfo.InvariantInfo) + " out of " + length.ToString(NumberFormatInfo.InvariantInfo) + ")"); - length = maxDumpSize; - } - if ((length < 0) || (length > buffer.Length - offset)) - { - length = buffer.Length - offset; - } - if (GetUseProtocolTextSetting(traceSource)) - { - string output = "<<" + HeaderEncoding.GetString(buffer, offset, length) + ">>"; - PrintLine(traceSource, TraceEventType.Verbose, 0, output); - return; - } - do - { - int n = Math.Min(length, 16); - string disp = String.Format(CultureInfo.CurrentCulture, "{0:X8} : ", offset); - for (int i = 0; i < n; ++i) - { - disp += String.Format(CultureInfo.CurrentCulture, "{0:X2}", buffer[offset + i]) + ((i == 7) ? '-' : ' '); - } - for (int i = n; i < 16; ++i) - { - disp += " "; - } - disp += ": "; - for (int i = 0; i < n; ++i) - { - disp += ((buffer[offset + i] < 0x20) || (buffer[offset + i] > 0x7e)) - ? '.' - : (char)(buffer[offset + i]); - } - PrintLine(traceSource, TraceEventType.Verbose, 0, disp); - offset += n; - length -= n; - } - while (length > 0); - } - - private class NclTraceSource : TraceSource - { - internal NclTraceSource(string name) : base(name) - { - } - /* - protected internal override string[] GetSupportedAttributes() - { - return Logging.SupportedAttributes; - }*/ - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs deleted file mode 100644 index 08310bdaf2..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/LoggingObject.cs +++ /dev/null @@ -1,597 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -// We have function based stack and thread based logging of basic behavior. We -// also now have the ability to run a "watch thread" which does basic hang detection -// and error-event based logging. The logging code buffers the callstack/picture -// of all COMNET threads, and upon error from an assert or a hang, it will open a file -// and dump the snapsnot. Future work will allow this to be configed by registry and -// to use Runtime based logging. We'd also like to have different levels of logging. - -namespace Microsoft.AspNet.Security.Windows -{ - using System; - - // BaseLoggingObject - used to disable logging, - // this is just a base class that does nothing. - - [Flags] - internal enum ThreadKinds - { - Unknown = 0x0000, - - // Mutually exclusive. - User = 0x0001, // Thread has entered via an API. - System = 0x0002, // Thread has entered via a system callback (e.g. completion port) or is our own thread. - - // Mutually exclusive. - Sync = 0x0004, // Thread should block. - Async = 0x0008, // Thread should not block. - - // Mutually exclusive, not always known for a user thread. Never changes. - Timer = 0x0010, // Thread is the timer thread. (Can't call user code.) - CompletionPort = 0x0020, // Thread is a ThreadPool completion-port thread. - Worker = 0x0040, // Thread is a ThreadPool worker thread. - Finalization = 0x0080, // Thread is the finalization thread. - Other = 0x0100, // Unknown source. - - OwnerMask = User | System, - SyncMask = Sync | Async, - SourceMask = Timer | CompletionPort | Worker | Finalization | Other, - - // Useful "macros" - SafeSources = SourceMask & ~(Timer | Finalization), // Methods that "unsafe" sources can call must be explicitly marked. - ThreadPool = CompletionPort | Worker, // Like Thread.CurrentThread.IsThreadPoolThread - } - - internal class BaseLoggingObject - { - internal BaseLoggingObject() - { - } - - internal virtual void EnterFunc(string funcname) - { - } - - internal virtual void LeaveFunc(string funcname) - { - } - - internal virtual void DumpArrayToConsole() - { - } - - internal virtual void PrintLine(string msg) - { - } - - internal virtual void DumpArray(bool shouldClose) - { - } - - internal virtual void DumpArrayToFile(bool shouldClose) - { - } - - internal virtual void Flush() - { - } - - internal virtual void Flush(bool close) - { - } - - internal virtual void LoggingMonitorTick() - { - } - - internal virtual void Dump(byte[] buffer) - { - } - - internal virtual void Dump(byte[] buffer, int length) - { - } - - internal virtual void Dump(byte[] buffer, int offset, int length) - { - } - - internal virtual void Dump(IntPtr pBuffer, int offset, int length) - { - } - } // class BaseLoggingObject - -#if TRAVE - /// - /// - /// - internal class LoggingObject : BaseLoggingObject { - public ArrayList _Logarray; - private Hashtable _ThreadNesting; - private int _AddCount; - private StreamWriter _Stream; - private int _IamAlive; - private int _LastIamAlive; - private bool _Finalized = false; - private double _NanosecondsPerTick; - private int _StartMilliseconds; - private long _StartTicks; - - internal LoggingObject() : base() { - _Logarray = new ArrayList(); - _ThreadNesting = new Hashtable(); - _AddCount = 0; - _IamAlive = 0; - _LastIamAlive = -1; - - if (GlobalLog.s_UsePerfCounter) { - long ticksPerSecond; - SafeNativeMethods.QueryPerformanceFrequency(out ticksPerSecond); - _NanosecondsPerTick = 10000000.0/(double)ticksPerSecond; - SafeNativeMethods.QueryPerformanceCounter(out _StartTicks); - } else { - _StartMilliseconds = Environment.TickCount; - } - } - - // - // LoggingMonitorTick - this function is run from the monitor thread, - // and used to check to see if there any hangs, ie no logging - // activitity - // - - internal override void LoggingMonitorTick() { - if ( _LastIamAlive == _IamAlive ) { - PrintLine("================= Error TIMEOUT - HANG DETECTED ================="); - DumpArray(true); - } - _LastIamAlive = _IamAlive; - } - - internal override void EnterFunc(string funcname) { - if (_Finalized) { - return; - } - IncNestingCount(); - ValidatePush(funcname); - PrintLine(funcname); - } - - internal override void LeaveFunc(string funcname) { - if (_Finalized) { - return; - } - PrintLine(funcname); - DecNestingCount(); - ValidatePop(funcname); - } - - internal override void DumpArrayToConsole() { - for (int i=0; i < _Logarray.Count; i++) { - Console.WriteLine((string) _Logarray[i]); - } - } - - internal override void PrintLine(string msg) { - if (_Finalized) { - return; - } - string spc = ""; - - _IamAlive++; - - spc = GetNestingString(); - - string tickString = ""; - - if (GlobalLog.s_UsePerfCounter) { - long nowTicks; - SafeNativeMethods.QueryPerformanceCounter(out nowTicks); - if (_StartTicks>nowTicks) { // counter reset, restart from 0 - _StartTicks = nowTicks; - } - nowTicks -= _StartTicks; - if (GlobalLog.s_UseTimeSpan) { - tickString = new TimeSpan((long)(nowTicks*_NanosecondsPerTick)).ToString(); - // note: TimeSpan().ToString() doesn't return the uSec part - // if its 0. .ToString() returns [H*]HH:MM:SS:uuuuuuu, hence 16 - if (tickString.Length < 16) { - tickString += ".0000000"; - } - } - else { - tickString = ((double)nowTicks*_NanosecondsPerTick/10000).ToString("f3"); - } - } - else { - int nowMilliseconds = Environment.TickCount; - if (_StartMilliseconds>nowMilliseconds) { - _StartMilliseconds = nowMilliseconds; - } - nowMilliseconds -= _StartMilliseconds; - if (GlobalLog.s_UseTimeSpan) { - tickString = new TimeSpan(nowMilliseconds*10000).ToString(); - // note: TimeSpan().ToString() doesn't return the uSec part - // if its 0. .ToString() returns [H*]HH:MM:SS:uuuuuuu, hence 16 - if (tickString.Length < 16) { - tickString += ".0000000"; - } - } - else { - tickString = nowMilliseconds.ToString(); - } - } - - uint threadId = 0; - - if (GlobalLog.s_UseThreadId) { - try { - object threadData = Thread.GetData(GlobalLog.s_ThreadIdSlot); - if (threadData!= null) { - threadId = (uint)threadData; - } - - } - catch(Exception exception) { - if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { - throw; - } - } - if (threadId == 0) { - threadId = UnsafeNclNativeMethods.GetCurrentThreadId(); - Thread.SetData(GlobalLog.s_ThreadIdSlot, threadId); - } - } - if (threadId == 0) { - threadId = (uint)Thread.CurrentThread.GetHashCode(); - } - - string str = "[" + threadId.ToString("x8") + "]" + " (" +tickString+ ") " + spc + msg; - - lock(this) { - _AddCount++; - _Logarray.Add(str); - int MaxLines = GlobalLog.s_DumpToConsole ? 0 : GlobalLog.MaxLinesBeforeSave; - if (_AddCount > MaxLines) { - _AddCount = 0; - DumpArray(false); - _Logarray = new ArrayList(); - } - } - } - - internal override void DumpArray(bool shouldClose) { - if ( GlobalLog.s_DumpToConsole ) { - DumpArrayToConsole(); - } else { - DumpArrayToFile(shouldClose); - } - } - - internal unsafe override void Dump(byte[] buffer, int offset, int length) { - //if (!GlobalLog.s_DumpWebData) { - // return; - //} - if (buffer==null) { - PrintLine("(null)"); - return; - } - if (offset > buffer.Length) { - PrintLine("(offset out of range)"); - return; - } - if (length > GlobalLog.s_MaxDumpSize) { - PrintLine("(printing " + GlobalLog.s_MaxDumpSize.ToString() + " out of " + length.ToString() + ")"); - length = GlobalLog.s_MaxDumpSize; - } - if ((length < 0) || (length > buffer.Length - offset)) { - length = buffer.Length - offset; - } - fixed (byte* pBuffer = buffer) { - Dump((IntPtr)pBuffer, offset, length); - } - } - - internal unsafe override void Dump(IntPtr pBuffer, int offset, int length) { - //if (!GlobalLog.s_DumpWebData) { - // return; - //} - if (pBuffer==IntPtr.Zero || length<0) { - PrintLine("(null)"); - return; - } - if (length > GlobalLog.s_MaxDumpSize) { - PrintLine("(printing " + GlobalLog.s_MaxDumpSize.ToString() + " out of " + length.ToString() + ")"); - length = GlobalLog.s_MaxDumpSize; - } - byte* buffer = (byte*)pBuffer + offset; - Dump(buffer, length); - } - - unsafe void Dump(byte* buffer, int length) { - do { - int offset = 0; - int n = Math.Min(length, 16); - string disp = ((IntPtr)buffer).ToString("X8") + " : " + offset.ToString("X8") + " : "; - byte current; - for (int i = 0; i < n; ++i) { - current = *(buffer + i); - disp += current.ToString("X2") + ((i == 7) ? '-' : ' '); - } - for (int i = n; i < 16; ++i) { - disp += " "; - } - disp += ": "; - for (int i = 0; i < n; ++i) { - current = *(buffer + i); - disp += ((current < 0x20) || (current > 0x7e)) ? '.' : (char)current; - } - PrintLine(disp); - offset += n; - buffer += n; - length -= n; - } while (length > 0); - } - - // SECURITY: This is dev-debugging class and we need some permissions - // to use it under trust-restricted environment as well. - [PermissionSet(SecurityAction.Assert, Name="FullTrust")] - internal override void DumpArrayToFile(bool shouldClose) { - lock (this) { - if (!shouldClose) { - if (_Stream==null) { - string mainLogFileRoot = GlobalLog.s_RootDirectory + "System.Net"; - string mainLogFile = mainLogFileRoot; - for (int k=0; k<20; k++) { - if (k>0) { - mainLogFile = mainLogFileRoot + "." + k.ToString(); - } - string fileName = mainLogFile + ".log"; - if (!File.Exists(fileName)) { - try { - _Stream = new StreamWriter(fileName); - break; - } - catch (Exception exception) { - if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { - throw; - } - if (exception is SecurityException || exception is UnauthorizedAccessException) { - // can't be CAS (we assert) this is an ACL issue - break; - } - } - } - } - if (_Stream==null) { - _Stream = StreamWriter.Null; - } - // write a header with information about the Process and the AppDomain - _Stream.Write("# MachineName: " + Environment.MachineName + "\r\n"); - _Stream.Write("# ProcessName: " + Process.GetCurrentProcess().ProcessName + " (pid: " + Process.GetCurrentProcess().Id + ")\r\n"); - _Stream.Write("# AppDomainId: " + AppDomain.CurrentDomain.Id + "\r\n"); - _Stream.Write("# CurrentIdentity: " + WindowsIdentity.GetCurrent().Name + "\r\n"); - _Stream.Write("# CommandLine: " + Environment.CommandLine + "\r\n"); - _Stream.Write("# ClrVersion: " + Environment.Version + "\r\n"); - _Stream.Write("# CreationDate: " + DateTime.Now.ToString("g") + "\r\n"); - } - } - try { - if (_Logarray!=null) { - for (int i=0; i<_Logarray.Count; i++) { - _Stream.Write((string)_Logarray[i]); - _Stream.Write("\r\n"); - } - - if (_Logarray.Count > 0 && _Stream != null) - _Stream.Flush(); - } - } - catch (Exception exception) { - if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { - throw; - } - } - if (shouldClose && _Stream!=null) { - try { - _Stream.Close(); - } - catch (ObjectDisposedException) { } - _Stream = null; - } - } - } - - internal override void Flush() { - Flush(false); - } - - internal override void Flush(bool close) { - lock (this) { - if (!GlobalLog.s_DumpToConsole) { - DumpArrayToFile(close); - _AddCount = 0; - } - } - } - - private class ThreadInfoData { - public ThreadInfoData(string indent) { - Indent = indent; - NestingStack = new Stack(); - } - public string Indent; - public Stack NestingStack; - }; - - string IndentString { - get { - string indent = " "; - Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()]; - if (!GlobalLog.s_DebugCallNesting) { - if (obj == null) { - _ThreadNesting[Thread.CurrentThread.GetHashCode()] = indent; - } else { - indent = (String) obj; - } - } else { - ThreadInfoData threadInfo = obj as ThreadInfoData; - if (threadInfo == null) { - threadInfo = new ThreadInfoData(indent); - _ThreadNesting[Thread.CurrentThread.GetHashCode()] = threadInfo; - } - indent = threadInfo.Indent; - } - return indent; - } - set { - Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()]; - if (obj == null) { - return; - } - if (!GlobalLog.s_DebugCallNesting) { - _ThreadNesting[Thread.CurrentThread.GetHashCode()] = value; - } else { - ThreadInfoData threadInfo = obj as ThreadInfoData; - if (threadInfo == null) { - threadInfo = new ThreadInfoData(value); - _ThreadNesting[Thread.CurrentThread.GetHashCode()] = threadInfo; - } - threadInfo.Indent = value; - } - } - } - - [System.Diagnostics.Conditional("TRAVE")] - private void IncNestingCount() { - IndentString = IndentString + " "; - } - - [System.Diagnostics.Conditional("TRAVE")] - private void DecNestingCount() { - string indent = IndentString; - if (indent.Length>1) { - try { - indent = indent.Substring(1); - } - catch { - indent = string.Empty; - } - } - if (indent.Length==0) { - indent = "< "; - } - IndentString = indent; - } - - private string GetNestingString() { - return IndentString; - } - - [System.Diagnostics.Conditional("TRAVE")] - private void ValidatePush(string name) { - if (GlobalLog.s_DebugCallNesting) { - Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()]; - ThreadInfoData threadInfo = obj as ThreadInfoData; - if (threadInfo == null) { - return; - } - threadInfo.NestingStack.Push(name); - } - } - - [System.Diagnostics.Conditional("TRAVE")] - private void ValidatePop(string name) { - if (GlobalLog.s_DebugCallNesting) { - try { - Object obj = _ThreadNesting[Thread.CurrentThread.GetHashCode()]; - ThreadInfoData threadInfo = obj as ThreadInfoData; - if (threadInfo == null) { - return; - } - if (threadInfo.NestingStack.Count == 0) { - PrintLine("++++====" + "Poped Empty Stack for :"+name); - } - string popedName = (string) threadInfo.NestingStack.Pop(); - string [] parsedList = popedName.Split(new char [] {'(',')',' ','.',':',',','#'}); - foreach (string element in parsedList) { - if (element != null && element.Length > 1 && name.IndexOf(element) != -1) { - return; - } - } - PrintLine("++++====" + "Expected:" + popedName + ": got :" + name + ": StackSize:"+threadInfo.NestingStack.Count); - // relevel the stack - while(threadInfo.NestingStack.Count>0) { - string popedName2 = (string) threadInfo.NestingStack.Pop(); - string [] parsedList2 = popedName2.Split(new char [] {'(',')',' ','.',':',',','#'}); - foreach (string element2 in parsedList2) { - if (element2 != null && element2.Length > 1 && name.IndexOf(element2) != -1) { - return; - } - } - } - } - catch { - PrintLine("++++====" + "ValidatePop failed for: "+name); - } - } - } - - - ~LoggingObject() { - if(!_Finalized) { - _Finalized = true; - lock(this) { - DumpArray(true); - } - } - } - - - } // class LoggingObject - - internal static class TraveHelper { - private static readonly string Hexizer = "0x{0:x}"; - internal static string ToHex(object value) { - return String.Format(Hexizer, value); - } - } -#endif // TRAVE - -#if TRAVE - internal class IntegerSwitch : BooleanSwitch { - public IntegerSwitch(string switchName, string switchDescription) : base(switchName, switchDescription) { - } - public new int Value { - get { - return base.SwitchSetting; - } - } - } - -#endif - - // class GlobalLog -} // namespace System.Net diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs deleted file mode 100644 index 008c713120..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/SR.cs +++ /dev/null @@ -1,647 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace System -{ - using System; - using System.Reflection; - using System.Globalization; - using System.Resources; - using System.Text; - using System.Threading; - using System.Security.Permissions; - using System.ComponentModel; - - /// - /// AutoGenerated resource class. Usage: - /// string s = SR.GetString(SR.MyIdenfitier); - /// - internal sealed class SR - { - internal const string security_ExtendedProtection_NoOSSupport = "security_ExtendedProtection_NoOSSupport"; - internal const string net_nonClsCompliantException = "net_nonClsCompliantException"; - internal const string net_illegalConfigWith = "net_illegalConfigWith"; - internal const string net_illegalConfigWithout = "net_illegalConfigWithout"; - internal const string net_baddate = "net_baddate"; - internal const string net_writestarted = "net_writestarted"; - internal const string net_clsmall = "net_clsmall"; - internal const string net_reqsubmitted = "net_reqsubmitted"; - internal const string net_rspsubmitted = "net_rspsubmitted"; - internal const string net_ftp_no_http_cmd = "net_ftp_no_http_cmd"; - internal const string net_ftp_invalid_method_name = "net_ftp_invalid_method_name"; - internal const string net_ftp_invalid_renameto = "net_ftp_invalid_renameto"; - internal const string net_ftp_no_defaultcreds = "net_ftp_no_defaultcreds"; - internal const string net_ftpnoresponse = "net_ftpnoresponse"; - internal const string net_ftp_response_invalid_format = "net_ftp_response_invalid_format"; - internal const string net_ftp_no_offsetforhttp = "net_ftp_no_offsetforhttp"; - internal const string net_ftp_invalid_uri = "net_ftp_invalid_uri"; - internal const string net_ftp_invalid_status_response = "net_ftp_invalid_status_response"; - internal const string net_ftp_server_failed_passive = "net_ftp_server_failed_passive"; - internal const string net_ftp_active_address_different = "net_ftp_active_address_different"; - internal const string net_ftp_proxy_does_not_support_ssl = "net_ftp_proxy_does_not_support_ssl"; - internal const string net_ftp_invalid_response_filename = "net_ftp_invalid_response_filename"; - internal const string net_ftp_unsupported_method = "net_ftp_unsupported_method"; - internal const string net_resubmitcanceled = "net_resubmitcanceled"; - internal const string net_redirect_perm = "net_redirect_perm"; - internal const string net_resubmitprotofailed = "net_resubmitprotofailed"; - internal const string net_needchunked = "net_needchunked"; - internal const string net_nochunked = "net_nochunked"; - internal const string net_nochunkuploadonhttp10 = "net_nochunkuploadonhttp10"; - internal const string net_connarg = "net_connarg"; - internal const string net_no100 = "net_no100"; - internal const string net_fromto = "net_fromto"; - internal const string net_rangetoosmall = "net_rangetoosmall"; - internal const string net_entitytoobig = "net_entitytoobig"; - internal const string net_invalidversion = "net_invalidversion"; - internal const string net_invalidstatus = "net_invalidstatus"; - internal const string net_toosmall = "net_toosmall"; - internal const string net_toolong = "net_toolong"; - internal const string net_connclosed = "net_connclosed"; - internal const string net_noseek = "net_noseek"; - internal const string net_servererror = "net_servererror"; - internal const string net_nouploadonget = "net_nouploadonget"; - internal const string net_mutualauthfailed = "net_mutualauthfailed"; - internal const string net_invasync = "net_invasync"; - internal const string net_inasync = "net_inasync"; - internal const string net_mustbeuri = "net_mustbeuri"; - internal const string net_format_shexp = "net_format_shexp"; - internal const string net_cannot_load_proxy_helper = "net_cannot_load_proxy_helper"; - internal const string net_invalid_host = "net_invalid_host"; - internal const string net_repcall = "net_repcall"; - internal const string net_wrongversion = "net_wrongversion"; - internal const string net_badmethod = "net_badmethod"; - internal const string net_io_notenoughbyteswritten = "net_io_notenoughbyteswritten"; - internal const string net_io_timeout_use_ge_zero = "net_io_timeout_use_ge_zero"; - internal const string net_io_timeout_use_gt_zero = "net_io_timeout_use_gt_zero"; - internal const string net_io_no_0timeouts = "net_io_no_0timeouts"; - internal const string net_requestaborted = "net_requestaborted"; - internal const string net_tooManyRedirections = "net_tooManyRedirections"; - internal const string net_authmodulenotregistered = "net_authmodulenotregistered"; - internal const string net_authschemenotregistered = "net_authschemenotregistered"; - internal const string net_proxyschemenotsupported = "net_proxyschemenotsupported"; - internal const string net_maxsrvpoints = "net_maxsrvpoints"; - internal const string net_unknown_prefix = "net_unknown_prefix"; - internal const string net_notconnected = "net_notconnected"; - internal const string net_notstream = "net_notstream"; - internal const string net_timeout = "net_timeout"; - internal const string net_nocontentlengthonget = "net_nocontentlengthonget"; - internal const string net_contentlengthmissing = "net_contentlengthmissing"; - internal const string net_nonhttpproxynotallowed = "net_nonhttpproxynotallowed"; - internal const string net_nottoken = "net_nottoken"; - internal const string net_rangetype = "net_rangetype"; - internal const string net_need_writebuffering = "net_need_writebuffering"; - internal const string net_securitypackagesupport = "net_securitypackagesupport"; - internal const string net_securityprotocolnotsupported = "net_securityprotocolnotsupported"; - internal const string net_nodefaultcreds = "net_nodefaultcreds"; - internal const string net_stopped = "net_stopped"; - internal const string net_udpconnected = "net_udpconnected"; - internal const string net_readonlystream = "net_readonlystream"; - internal const string net_writeonlystream = "net_writeonlystream"; - internal const string net_no_concurrent_io_allowed = "net_no_concurrent_io_allowed"; - internal const string net_needmorethreads = "net_needmorethreads"; - internal const string net_MethodNotImplementedException = "net_MethodNotImplementedException"; - internal const string net_PropertyNotImplementedException = "net_PropertyNotImplementedException"; - internal const string net_MethodNotSupportedException = "net_MethodNotSupportedException"; - internal const string net_PropertyNotSupportedException = "net_PropertyNotSupportedException"; - internal const string net_ProtocolNotSupportedException = "net_ProtocolNotSupportedException"; - internal const string net_SelectModeNotSupportedException = "net_SelectModeNotSupportedException"; - internal const string net_InvalidSocketHandle = "net_InvalidSocketHandle"; - internal const string net_InvalidAddressFamily = "net_InvalidAddressFamily"; - internal const string net_InvalidEndPointAddressFamily = "net_InvalidEndPointAddressFamily"; - internal const string net_InvalidSocketAddressSize = "net_InvalidSocketAddressSize"; - internal const string net_invalidAddressList = "net_invalidAddressList"; - internal const string net_invalidPingBufferSize = "net_invalidPingBufferSize"; - internal const string net_cant_perform_during_shutdown = "net_cant_perform_during_shutdown"; - internal const string net_cant_create_environment = "net_cant_create_environment"; - internal const string net_completed_result = "net_completed_result"; - internal const string net_protocol_invalid_family = "net_protocol_invalid_family"; - internal const string net_protocol_invalid_multicast_family = "net_protocol_invalid_multicast_family"; - internal const string net_empty_osinstalltype = "net_empty_osinstalltype"; - internal const string net_unknown_osinstalltype = "net_unknown_osinstalltype"; - internal const string net_cant_determine_osinstalltype = "net_cant_determine_osinstalltype"; - internal const string net_osinstalltype = "net_osinstalltype"; - internal const string net_entire_body_not_written = "net_entire_body_not_written"; - internal const string net_must_provide_request_body = "net_must_provide_request_body"; - internal const string net_ssp_dont_support_cbt = "net_ssp_dont_support_cbt"; - internal const string net_sockets_zerolist = "net_sockets_zerolist"; - internal const string net_sockets_blocking = "net_sockets_blocking"; - internal const string net_sockets_useblocking = "net_sockets_useblocking"; - internal const string net_sockets_select = "net_sockets_select"; - internal const string net_sockets_toolarge_select = "net_sockets_toolarge_select"; - internal const string net_sockets_empty_select = "net_sockets_empty_select"; - internal const string net_sockets_mustbind = "net_sockets_mustbind"; - internal const string net_sockets_mustlisten = "net_sockets_mustlisten"; - internal const string net_sockets_mustnotlisten = "net_sockets_mustnotlisten"; - internal const string net_sockets_mustnotbebound = "net_sockets_mustnotbebound"; - internal const string net_sockets_namedmustnotbebound = "net_sockets_namedmustnotbebound"; - internal const string net_sockets_invalid_socketinformation = "net_sockets_invalid_socketinformation"; - internal const string net_sockets_invalid_ipaddress_length = "net_sockets_invalid_ipaddress_length"; - internal const string net_sockets_invalid_optionValue = "net_sockets_invalid_optionValue"; - internal const string net_sockets_invalid_optionValue_all = "net_sockets_invalid_optionValue_all"; - internal const string net_sockets_invalid_dnsendpoint = "net_sockets_invalid_dnsendpoint"; - internal const string net_sockets_disconnectedConnect = "net_sockets_disconnectedConnect"; - internal const string net_sockets_disconnectedAccept = "net_sockets_disconnectedAccept"; - internal const string net_tcplistener_mustbestopped = "net_tcplistener_mustbestopped"; - internal const string net_sockets_no_duplicate_async = "net_sockets_no_duplicate_async"; - internal const string net_socketopinprogress = "net_socketopinprogress"; - internal const string net_buffercounttoosmall = "net_buffercounttoosmall"; - internal const string net_multibuffernotsupported = "net_multibuffernotsupported"; - internal const string net_ambiguousbuffers = "net_ambiguousbuffers"; - internal const string net_sockets_ipv6only = "net_sockets_ipv6only"; - internal const string net_perfcounter_initialized_success = "net_perfcounter_initialized_success"; - internal const string net_perfcounter_initialized_error = "net_perfcounter_initialized_error"; - internal const string net_perfcounter_nocategory = "net_perfcounter_nocategory"; - internal const string net_perfcounter_initialization_started = "net_perfcounter_initialization_started"; - internal const string net_perfcounter_cant_queue_workitem = "net_perfcounter_cant_queue_workitem"; - internal const string net_config_proxy = "net_config_proxy"; - internal const string net_config_proxy_module_not_public = "net_config_proxy_module_not_public"; - internal const string net_config_authenticationmodules = "net_config_authenticationmodules"; - internal const string net_config_webrequestmodules = "net_config_webrequestmodules"; - internal const string net_config_requestcaching = "net_config_requestcaching"; - internal const string net_config_section_permission = "net_config_section_permission"; - internal const string net_config_element_permission = "net_config_element_permission"; - internal const string net_config_property_permission = "net_config_property_permission"; - internal const string net_WebResponseParseError_InvalidHeaderName = "net_WebResponseParseError_InvalidHeaderName"; - internal const string net_WebResponseParseError_InvalidContentLength = "net_WebResponseParseError_InvalidContentLength"; - internal const string net_WebResponseParseError_IncompleteHeaderLine = "net_WebResponseParseError_IncompleteHeaderLine"; - internal const string net_WebResponseParseError_CrLfError = "net_WebResponseParseError_CrLfError"; - internal const string net_WebResponseParseError_InvalidChunkFormat = "net_WebResponseParseError_InvalidChunkFormat"; - internal const string net_WebResponseParseError_UnexpectedServerResponse = "net_WebResponseParseError_UnexpectedServerResponse"; - internal const string net_webstatus_Success = "net_webstatus_Success"; - internal const string net_webstatus_NameResolutionFailure = "net_webstatus_NameResolutionFailure"; - internal const string net_webstatus_ConnectFailure = "net_webstatus_ConnectFailure"; - internal const string net_webstatus_ReceiveFailure = "net_webstatus_ReceiveFailure"; - internal const string net_webstatus_SendFailure = "net_webstatus_SendFailure"; - internal const string net_webstatus_PipelineFailure = "net_webstatus_PipelineFailure"; - internal const string net_webstatus_RequestCanceled = "net_webstatus_RequestCanceled"; - internal const string net_webstatus_ConnectionClosed = "net_webstatus_ConnectionClosed"; - internal const string net_webstatus_TrustFailure = "net_webstatus_TrustFailure"; - internal const string net_webstatus_SecureChannelFailure = "net_webstatus_SecureChannelFailure"; - internal const string net_webstatus_ServerProtocolViolation = "net_webstatus_ServerProtocolViolation"; - internal const string net_webstatus_KeepAliveFailure = "net_webstatus_KeepAliveFailure"; - internal const string net_webstatus_ProxyNameResolutionFailure = "net_webstatus_ProxyNameResolutionFailure"; - internal const string net_webstatus_MessageLengthLimitExceeded = "net_webstatus_MessageLengthLimitExceeded"; - internal const string net_webstatus_CacheEntryNotFound = "net_webstatus_CacheEntryNotFound"; - internal const string net_webstatus_RequestProhibitedByCachePolicy = "net_webstatus_RequestProhibitedByCachePolicy"; - internal const string net_webstatus_Timeout = "net_webstatus_Timeout"; - internal const string net_webstatus_RequestProhibitedByProxy = "net_webstatus_RequestProhibitedByProxy"; - internal const string net_InvalidStatusCode = "net_InvalidStatusCode"; - internal const string net_ftpstatuscode_ServiceNotAvailable = "net_ftpstatuscode_ServiceNotAvailable"; - internal const string net_ftpstatuscode_CantOpenData = "net_ftpstatuscode_CantOpenData"; - internal const string net_ftpstatuscode_ConnectionClosed = "net_ftpstatuscode_ConnectionClosed"; - internal const string net_ftpstatuscode_ActionNotTakenFileUnavailableOrBusy = "net_ftpstatuscode_ActionNotTakenFileUnavailableOrBusy"; - internal const string net_ftpstatuscode_ActionAbortedLocalProcessingError = "net_ftpstatuscode_ActionAbortedLocalProcessingError"; - internal const string net_ftpstatuscode_ActionNotTakenInsufficentSpace = "net_ftpstatuscode_ActionNotTakenInsufficentSpace"; - internal const string net_ftpstatuscode_CommandSyntaxError = "net_ftpstatuscode_CommandSyntaxError"; - internal const string net_ftpstatuscode_ArgumentSyntaxError = "net_ftpstatuscode_ArgumentSyntaxError"; - internal const string net_ftpstatuscode_CommandNotImplemented = "net_ftpstatuscode_CommandNotImplemented"; - internal const string net_ftpstatuscode_BadCommandSequence = "net_ftpstatuscode_BadCommandSequence"; - internal const string net_ftpstatuscode_NotLoggedIn = "net_ftpstatuscode_NotLoggedIn"; - internal const string net_ftpstatuscode_AccountNeeded = "net_ftpstatuscode_AccountNeeded"; - internal const string net_ftpstatuscode_ActionNotTakenFileUnavailable = "net_ftpstatuscode_ActionNotTakenFileUnavailable"; - internal const string net_ftpstatuscode_ActionAbortedUnknownPageType = "net_ftpstatuscode_ActionAbortedUnknownPageType"; - internal const string net_ftpstatuscode_FileActionAborted = "net_ftpstatuscode_FileActionAborted"; - internal const string net_ftpstatuscode_ActionNotTakenFilenameNotAllowed = "net_ftpstatuscode_ActionNotTakenFilenameNotAllowed"; - internal const string net_httpstatuscode_NoContent = "net_httpstatuscode_NoContent"; - internal const string net_httpstatuscode_NonAuthoritativeInformation = "net_httpstatuscode_NonAuthoritativeInformation"; - internal const string net_httpstatuscode_ResetContent = "net_httpstatuscode_ResetContent"; - internal const string net_httpstatuscode_PartialContent = "net_httpstatuscode_PartialContent"; - internal const string net_httpstatuscode_MultipleChoices = "net_httpstatuscode_MultipleChoices"; - internal const string net_httpstatuscode_Ambiguous = "net_httpstatuscode_Ambiguous"; - internal const string net_httpstatuscode_MovedPermanently = "net_httpstatuscode_MovedPermanently"; - internal const string net_httpstatuscode_Moved = "net_httpstatuscode_Moved"; - internal const string net_httpstatuscode_Found = "net_httpstatuscode_Found"; - internal const string net_httpstatuscode_Redirect = "net_httpstatuscode_Redirect"; - internal const string net_httpstatuscode_SeeOther = "net_httpstatuscode_SeeOther"; - internal const string net_httpstatuscode_RedirectMethod = "net_httpstatuscode_RedirectMethod"; - internal const string net_httpstatuscode_NotModified = "net_httpstatuscode_NotModified"; - internal const string net_httpstatuscode_UseProxy = "net_httpstatuscode_UseProxy"; - internal const string net_httpstatuscode_TemporaryRedirect = "net_httpstatuscode_TemporaryRedirect"; - internal const string net_httpstatuscode_RedirectKeepVerb = "net_httpstatuscode_RedirectKeepVerb"; - internal const string net_httpstatuscode_BadRequest = "net_httpstatuscode_BadRequest"; - internal const string net_httpstatuscode_Unauthorized = "net_httpstatuscode_Unauthorized"; - internal const string net_httpstatuscode_PaymentRequired = "net_httpstatuscode_PaymentRequired"; - internal const string net_httpstatuscode_Forbidden = "net_httpstatuscode_Forbidden"; - internal const string net_httpstatuscode_NotFound = "net_httpstatuscode_NotFound"; - internal const string net_httpstatuscode_MethodNotAllowed = "net_httpstatuscode_MethodNotAllowed"; - internal const string net_httpstatuscode_NotAcceptable = "net_httpstatuscode_NotAcceptable"; - internal const string net_httpstatuscode_ProxyAuthenticationRequired = "net_httpstatuscode_ProxyAuthenticationRequired"; - internal const string net_httpstatuscode_RequestTimeout = "net_httpstatuscode_RequestTimeout"; - internal const string net_httpstatuscode_Conflict = "net_httpstatuscode_Conflict"; - internal const string net_httpstatuscode_Gone = "net_httpstatuscode_Gone"; - internal const string net_httpstatuscode_LengthRequired = "net_httpstatuscode_LengthRequired"; - internal const string net_httpstatuscode_InternalServerError = "net_httpstatuscode_InternalServerError"; - internal const string net_httpstatuscode_NotImplemented = "net_httpstatuscode_NotImplemented"; - internal const string net_httpstatuscode_BadGateway = "net_httpstatuscode_BadGateway"; - internal const string net_httpstatuscode_ServiceUnavailable = "net_httpstatuscode_ServiceUnavailable"; - internal const string net_httpstatuscode_GatewayTimeout = "net_httpstatuscode_GatewayTimeout"; - internal const string net_httpstatuscode_HttpVersionNotSupported = "net_httpstatuscode_HttpVersionNotSupported"; - internal const string net_uri_BadScheme = "net_uri_BadScheme"; - internal const string net_uri_BadFormat = "net_uri_BadFormat"; - internal const string net_uri_BadUserPassword = "net_uri_BadUserPassword"; - internal const string net_uri_BadHostName = "net_uri_BadHostName"; - internal const string net_uri_BadAuthority = "net_uri_BadAuthority"; - internal const string net_uri_BadAuthorityTerminator = "net_uri_BadAuthorityTerminator"; - internal const string net_uri_EmptyUri = "net_uri_EmptyUri"; - internal const string net_uri_BadString = "net_uri_BadString"; - internal const string net_uri_MustRootedPath = "net_uri_MustRootedPath"; - internal const string net_uri_BadPort = "net_uri_BadPort"; - internal const string net_uri_SizeLimit = "net_uri_SizeLimit"; - internal const string net_uri_SchemeLimit = "net_uri_SchemeLimit"; - internal const string net_uri_NotAbsolute = "net_uri_NotAbsolute"; - internal const string net_uri_PortOutOfRange = "net_uri_PortOutOfRange"; - internal const string net_uri_UserDrivenParsing = "net_uri_UserDrivenParsing"; - internal const string net_uri_AlreadyRegistered = "net_uri_AlreadyRegistered"; - internal const string net_uri_NeedFreshParser = "net_uri_NeedFreshParser"; - internal const string net_uri_CannotCreateRelative = "net_uri_CannotCreateRelative"; - internal const string net_uri_InvalidUriKind = "net_uri_InvalidUriKind"; - internal const string net_uri_BadUnicodeHostForIdn = "net_uri_BadUnicodeHostForIdn"; - internal const string net_uri_GenericAuthorityNotDnsSafe = "net_uri_GenericAuthorityNotDnsSafe"; - internal const string net_uri_NotJustSerialization = "net_uri_NotJustSerialization"; - internal const string net_emptystringset = "net_emptystringset"; - internal const string net_emptystringcall = "net_emptystringcall"; - internal const string net_headers_req = "net_headers_req"; - internal const string net_headers_rsp = "net_headers_rsp"; - internal const string net_headers_toolong = "net_headers_toolong"; - internal const string net_WebHeaderInvalidControlChars = "net_WebHeaderInvalidControlChars"; - internal const string net_WebHeaderInvalidCRLFChars = "net_WebHeaderInvalidCRLFChars"; - internal const string net_WebHeaderInvalidHeaderChars = "net_WebHeaderInvalidHeaderChars"; - internal const string net_WebHeaderInvalidNonAsciiChars = "net_WebHeaderInvalidNonAsciiChars"; - internal const string net_WebHeaderMissingColon = "net_WebHeaderMissingColon"; - internal const string net_headerrestrict = "net_headerrestrict"; - internal const string net_io_completionportwasbound = "net_io_completionportwasbound"; - internal const string net_io_writefailure = "net_io_writefailure"; - internal const string net_io_readfailure = "net_io_readfailure"; - internal const string net_io_connectionclosed = "net_io_connectionclosed"; - internal const string net_io_transportfailure = "net_io_transportfailure"; - internal const string net_io_internal_bind = "net_io_internal_bind"; - internal const string net_io_invalidasyncresult = "net_io_invalidasyncresult"; - internal const string net_io_invalidnestedcall = "net_io_invalidnestedcall"; - internal const string net_io_invalidendcall = "net_io_invalidendcall"; - internal const string net_io_must_be_rw_stream = "net_io_must_be_rw_stream"; - internal const string net_io_header_id = "net_io_header_id"; - internal const string net_io_out_range = "net_io_out_range"; - internal const string net_io_encrypt = "net_io_encrypt"; - internal const string net_io_decrypt = "net_io_decrypt"; - internal const string net_io_read = "net_io_read"; - internal const string net_io_write = "net_io_write"; - internal const string net_io_eof = "net_io_eof"; - internal const string net_io_async_result = "net_io_async_result"; - internal const string net_listener_mustcall = "net_listener_mustcall"; - internal const string net_listener_mustcompletecall = "net_listener_mustcompletecall"; - internal const string net_listener_callinprogress = "net_listener_callinprogress"; - internal const string net_listener_scheme = "net_listener_scheme"; - internal const string net_listener_host = "net_listener_host"; - internal const string net_listener_slash = "net_listener_slash"; - internal const string net_listener_repcall = "net_listener_repcall"; - internal const string net_listener_invalid_cbt_type = "net_listener_invalid_cbt_type"; - internal const string net_listener_no_spns = "net_listener_no_spns"; - internal const string net_listener_cannot_set_custom_cbt = "net_listener_cannot_set_custom_cbt"; - internal const string net_listener_cbt_not_supported = "net_listener_cbt_not_supported"; - internal const string net_listener_detach_error = "net_listener_detach_error"; - internal const string net_listener_close_urlgroup_error = "net_listener_close_urlgroup_error"; - internal const string net_tls_version = "net_tls_version"; - internal const string net_perm_target = "net_perm_target"; - internal const string net_perm_both_regex = "net_perm_both_regex"; - internal const string net_perm_none = "net_perm_none"; - internal const string net_perm_attrib_count = "net_perm_attrib_count"; - internal const string net_perm_invalid_val = "net_perm_invalid_val"; - internal const string net_perm_attrib_multi = "net_perm_attrib_multi"; - internal const string net_perm_epname = "net_perm_epname"; - internal const string net_perm_invalid_val_in_element = "net_perm_invalid_val_in_element"; - internal const string net_invalid_ip_addr = "net_invalid_ip_addr"; - internal const string dns_bad_ip_address = "dns_bad_ip_address"; - internal const string net_bad_mac_address = "net_bad_mac_address"; - internal const string net_ping = "net_ping"; - internal const string net_bad_ip_address_prefix = "net_bad_ip_address_prefix"; - internal const string net_max_ip_address_list_length_exceeded = "net_max_ip_address_list_length_exceeded"; - internal const string net_ipv4_not_installed = "net_ipv4_not_installed"; - internal const string net_ipv6_not_installed = "net_ipv6_not_installed"; - internal const string net_webclient = "net_webclient"; - internal const string net_webclient_ContentType = "net_webclient_ContentType"; - internal const string net_webclient_Multipart = "net_webclient_Multipart"; - internal const string net_webclient_no_concurrent_io_allowed = "net_webclient_no_concurrent_io_allowed"; - internal const string net_webclient_invalid_baseaddress = "net_webclient_invalid_baseaddress"; - internal const string net_container_add_cookie = "net_container_add_cookie"; - internal const string net_cookie_invalid = "net_cookie_invalid"; - internal const string net_cookie_size = "net_cookie_size"; - internal const string net_cookie_parse_header = "net_cookie_parse_header"; - internal const string net_cookie_attribute = "net_cookie_attribute"; - internal const string net_cookie_format = "net_cookie_format"; - internal const string net_cookie_exists = "net_cookie_exists"; - internal const string net_cookie_capacity_range = "net_cookie_capacity_range"; - internal const string net_set_token = "net_set_token"; - internal const string net_revert_token = "net_revert_token"; - internal const string net_ssl_io_async_context = "net_ssl_io_async_context"; - internal const string net_ssl_io_encrypt = "net_ssl_io_encrypt"; - internal const string net_ssl_io_decrypt = "net_ssl_io_decrypt"; - internal const string net_ssl_io_context_expired = "net_ssl_io_context_expired"; - internal const string net_ssl_io_handshake_start = "net_ssl_io_handshake_start"; - internal const string net_ssl_io_handshake = "net_ssl_io_handshake"; - internal const string net_ssl_io_frame = "net_ssl_io_frame"; - internal const string net_ssl_io_corrupted = "net_ssl_io_corrupted"; - internal const string net_ssl_io_cert_validation = "net_ssl_io_cert_validation"; - internal const string net_ssl_io_invalid_end_call = "net_ssl_io_invalid_end_call"; - internal const string net_ssl_io_invalid_begin_call = "net_ssl_io_invalid_begin_call"; - internal const string net_ssl_io_no_server_cert = "net_ssl_io_no_server_cert"; - internal const string net_auth_bad_client_creds = "net_auth_bad_client_creds"; - internal const string net_auth_bad_client_creds_or_target_mismatch = "net_auth_bad_client_creds_or_target_mismatch"; - internal const string net_auth_context_expectation = "net_auth_context_expectation"; - internal const string net_auth_context_expectation_remote = "net_auth_context_expectation_remote"; - internal const string net_auth_supported_impl_levels = "net_auth_supported_impl_levels"; - internal const string net_auth_no_anonymous_support = "net_auth_no_anonymous_support"; - internal const string net_auth_reauth = "net_auth_reauth"; - internal const string net_auth_noauth = "net_auth_noauth"; - internal const string net_auth_client_server = "net_auth_client_server"; - internal const string net_auth_noencryption = "net_auth_noencryption"; - internal const string net_auth_SSPI = "net_auth_SSPI"; - internal const string net_auth_failure = "net_auth_failure"; - internal const string net_auth_eof = "net_auth_eof"; - internal const string net_auth_alert = "net_auth_alert"; - internal const string net_auth_ignored_reauth = "net_auth_ignored_reauth"; - internal const string net_auth_empty_read = "net_auth_empty_read"; - internal const string net_auth_message_not_encrypted = "net_auth_message_not_encrypted"; - internal const string net_auth_must_specify_extended_protection_scheme = "net_auth_must_specify_extended_protection_scheme"; - internal const string net_frame_size = "net_frame_size"; - internal const string net_frame_read_io = "net_frame_read_io"; - internal const string net_frame_read_size = "net_frame_read_size"; - internal const string net_frame_max_size = "net_frame_max_size"; - internal const string net_jscript_load = "net_jscript_load"; - internal const string net_proxy_not_gmt = "net_proxy_not_gmt"; - internal const string net_proxy_invalid_dayofweek = "net_proxy_invalid_dayofweek"; - internal const string net_proxy_invalid_url_format = "net_proxy_invalid_url_format"; - internal const string net_param_not_string = "net_param_not_string"; - internal const string net_value_cannot_be_negative = "net_value_cannot_be_negative"; - internal const string net_invalid_offset = "net_invalid_offset"; - internal const string net_offset_plus_count = "net_offset_plus_count"; - internal const string net_cannot_be_false = "net_cannot_be_false"; - internal const string net_invalid_enum = "net_invalid_enum"; - internal const string net_listener_already = "net_listener_already"; - internal const string net_cache_shadowstream_not_writable = "net_cache_shadowstream_not_writable"; - internal const string net_cache_validator_fail = "net_cache_validator_fail"; - internal const string net_cache_access_denied = "net_cache_access_denied"; - internal const string net_cache_validator_result = "net_cache_validator_result"; - internal const string net_cache_retrieve_failure = "net_cache_retrieve_failure"; - internal const string net_cache_not_supported_body = "net_cache_not_supported_body"; - internal const string net_cache_not_supported_command = "net_cache_not_supported_command"; - internal const string net_cache_not_accept_response = "net_cache_not_accept_response"; - internal const string net_cache_method_failed = "net_cache_method_failed"; - internal const string net_cache_key_failed = "net_cache_key_failed"; - internal const string net_cache_no_stream = "net_cache_no_stream"; - internal const string net_cache_unsupported_partial_stream = "net_cache_unsupported_partial_stream"; - internal const string net_cache_not_configured = "net_cache_not_configured"; - internal const string net_cache_non_seekable_stream_not_supported = "net_cache_non_seekable_stream_not_supported"; - internal const string net_invalid_cast = "net_invalid_cast"; - internal const string net_collection_readonly = "net_collection_readonly"; - internal const string net_not_ipermission = "net_not_ipermission"; - internal const string net_no_classname = "net_no_classname"; - internal const string net_no_typename = "net_no_typename"; - internal const string net_array_too_small = "net_array_too_small"; - internal const string net_servicePointAddressNotSupportedInHostMode = "net_servicePointAddressNotSupportedInHostMode"; - internal const string net_Websockets_AlreadyOneOutstandingOperation = "net_Websockets_AlreadyOneOutstandingOperation"; - internal const string net_Websockets_WebSocketBaseFaulted = "net_Websockets_WebSocketBaseFaulted"; - internal const string net_WebSockets_NativeSendResponseHeaders = "net_WebSockets_NativeSendResponseHeaders"; - internal const string net_WebSockets_Generic = "net_WebSockets_Generic"; - internal const string net_WebSockets_NotAWebSocket_Generic = "net_WebSockets_NotAWebSocket_Generic"; - internal const string net_WebSockets_UnsupportedWebSocketVersion_Generic = "net_WebSockets_UnsupportedWebSocketVersion_Generic"; - internal const string net_WebSockets_HeaderError_Generic = "net_WebSockets_HeaderError_Generic"; - internal const string net_WebSockets_UnsupportedProtocol_Generic = "net_WebSockets_UnsupportedProtocol_Generic"; - internal const string net_WebSockets_UnsupportedPlatform = "net_WebSockets_UnsupportedPlatform"; - internal const string net_WebSockets_AcceptNotAWebSocket = "net_WebSockets_AcceptNotAWebSocket"; - internal const string net_WebSockets_AcceptUnsupportedWebSocketVersion = "net_WebSockets_AcceptUnsupportedWebSocketVersion"; - internal const string net_WebSockets_AcceptHeaderNotFound = "net_WebSockets_AcceptHeaderNotFound"; - internal const string net_WebSockets_AcceptUnsupportedProtocol = "net_WebSockets_AcceptUnsupportedProtocol"; - internal const string net_WebSockets_ClientAcceptingNoProtocols = "net_WebSockets_ClientAcceptingNoProtocols"; - internal const string net_WebSockets_ClientSecWebSocketProtocolsBlank = "net_WebSockets_ClientSecWebSocketProtocolsBlank"; - internal const string net_WebSockets_ArgumentOutOfRange_TooSmall = "net_WebSockets_ArgumentOutOfRange_TooSmall"; - internal const string net_WebSockets_ArgumentOutOfRange_InternalBuffer = "net_WebSockets_ArgumentOutOfRange_InternalBuffer"; - internal const string net_WebSockets_ArgumentOutOfRange_TooBig = "net_WebSockets_ArgumentOutOfRange_TooBig"; - internal const string net_WebSockets_InvalidState_Generic = "net_WebSockets_InvalidState_Generic"; - internal const string net_WebSockets_InvalidState_ClosedOrAborted = "net_WebSockets_InvalidState_ClosedOrAborted"; - internal const string net_WebSockets_InvalidState = "net_WebSockets_InvalidState"; - internal const string net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync = "net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync"; - internal const string net_WebSockets_InvalidMessageType = "net_WebSockets_InvalidMessageType"; - internal const string net_WebSockets_InvalidBufferType = "net_WebSockets_InvalidBufferType"; - internal const string net_WebSockets_InvalidMessageType_Generic = "net_WebSockets_InvalidMessageType_Generic"; - internal const string net_WebSockets_Argument_InvalidMessageType = "net_WebSockets_Argument_InvalidMessageType"; - internal const string net_WebSockets_ConnectionClosedPrematurely_Generic = "net_WebSockets_ConnectionClosedPrematurely_Generic"; - internal const string net_WebSockets_InvalidCharInProtocolString = "net_WebSockets_InvalidCharInProtocolString"; - internal const string net_WebSockets_InvalidEmptySubProtocol = "net_WebSockets_InvalidEmptySubProtocol"; - internal const string net_WebSockets_ReasonNotNull = "net_WebSockets_ReasonNotNull"; - internal const string net_WebSockets_InvalidCloseStatusCode = "net_WebSockets_InvalidCloseStatusCode"; - internal const string net_WebSockets_InvalidCloseStatusDescription = "net_WebSockets_InvalidCloseStatusDescription"; - internal const string net_WebSockets_Scheme = "net_WebSockets_Scheme"; - internal const string net_WebSockets_AlreadyStarted = "net_WebSockets_AlreadyStarted"; - internal const string net_WebSockets_Connect101Expected = "net_WebSockets_Connect101Expected"; - internal const string net_WebSockets_InvalidResponseHeader = "net_WebSockets_InvalidResponseHeader"; - internal const string net_WebSockets_NotConnected = "net_WebSockets_NotConnected"; - internal const string net_WebSockets_InvalidRegistration = "net_WebSockets_InvalidRegistration"; - internal const string net_WebSockets_NoDuplicateProtocol = "net_WebSockets_NoDuplicateProtocol"; - internal const string net_log_exception = "net_log_exception"; - internal const string net_log_listener_delegate_exception = "net_log_listener_delegate_exception"; - internal const string net_log_listener_unsupported_authentication_scheme = "net_log_listener_unsupported_authentication_scheme"; - internal const string net_log_listener_unmatched_authentication_scheme = "net_log_listener_unmatched_authentication_scheme"; - internal const string net_log_listener_create_valid_identity_failed = "net_log_listener_create_valid_identity_failed"; - internal const string net_log_listener_httpsys_registry_null = "net_log_listener_httpsys_registry_null"; - internal const string net_log_listener_httpsys_registry_error = "net_log_listener_httpsys_registry_error"; - internal const string net_log_listener_cant_convert_raw_path = "net_log_listener_cant_convert_raw_path"; - internal const string net_log_listener_cant_convert_percent_value = "net_log_listener_cant_convert_percent_value"; - internal const string net_log_listener_cant_convert_bytes = "net_log_listener_cant_convert_bytes"; - internal const string net_log_listener_cant_convert_to_utf8 = "net_log_listener_cant_convert_to_utf8"; - internal const string net_log_listener_cant_create_uri = "net_log_listener_cant_create_uri"; - internal const string net_log_listener_no_cbt_disabled = "net_log_listener_no_cbt_disabled"; - internal const string net_log_listener_no_cbt_http = "net_log_listener_no_cbt_http"; - internal const string net_log_listener_no_cbt_platform = "net_log_listener_no_cbt_platform"; - internal const string net_log_listener_no_cbt_trustedproxy = "net_log_listener_no_cbt_trustedproxy"; - internal const string net_log_listener_cbt = "net_log_listener_cbt"; - internal const string net_log_listener_no_spn_kerberos = "net_log_listener_no_spn_kerberos"; - internal const string net_log_listener_no_spn_disabled = "net_log_listener_no_spn_disabled"; - internal const string net_log_listener_no_spn_cbt = "net_log_listener_no_spn_cbt"; - internal const string net_log_listener_no_spn_platform = "net_log_listener_no_spn_platform"; - internal const string net_log_listener_no_spn_whensupported = "net_log_listener_no_spn_whensupported"; - internal const string net_log_listener_no_spn_loopback = "net_log_listener_no_spn_loopback"; - internal const string net_log_listener_spn = "net_log_listener_spn"; - internal const string net_log_listener_spn_passed = "net_log_listener_spn_passed"; - internal const string net_log_listener_spn_failed = "net_log_listener_spn_failed"; - internal const string net_log_listener_spn_failed_always = "net_log_listener_spn_failed_always"; - internal const string net_log_listener_spn_failed_empty = "net_log_listener_spn_failed_empty"; - internal const string net_log_listener_spn_failed_dump = "net_log_listener_spn_failed_dump"; - internal const string net_log_listener_spn_add = "net_log_listener_spn_add"; - internal const string net_log_listener_spn_not_add = "net_log_listener_spn_not_add"; - internal const string net_log_listener_spn_remove = "net_log_listener_spn_remove"; - internal const string net_log_listener_spn_not_remove = "net_log_listener_spn_not_remove"; - internal const string net_log_sspi_enumerating_security_packages = "net_log_sspi_enumerating_security_packages"; - internal const string net_log_sspi_security_package_not_found = "net_log_sspi_security_package_not_found"; - internal const string net_log_sspi_security_context_input_buffer = "net_log_sspi_security_context_input_buffer"; - internal const string net_log_sspi_security_context_input_buffers = "net_log_sspi_security_context_input_buffers"; - internal const string net_log_sspi_selected_cipher_suite = "net_log_sspi_selected_cipher_suite"; - internal const string net_log_remote_certificate = "net_log_remote_certificate"; - internal const string net_log_locating_private_key_for_certificate = "net_log_locating_private_key_for_certificate"; - internal const string net_log_cert_is_of_type_2 = "net_log_cert_is_of_type_2"; - internal const string net_log_found_cert_in_store = "net_log_found_cert_in_store"; - internal const string net_log_did_not_find_cert_in_store = "net_log_did_not_find_cert_in_store"; - internal const string net_log_open_store_failed = "net_log_open_store_failed"; - internal const string net_log_got_certificate_from_delegate = "net_log_got_certificate_from_delegate"; - internal const string net_log_no_delegate_and_have_no_client_cert = "net_log_no_delegate_and_have_no_client_cert"; - internal const string net_log_no_delegate_but_have_client_cert = "net_log_no_delegate_but_have_client_cert"; - internal const string net_log_attempting_restart_using_cert = "net_log_attempting_restart_using_cert"; - internal const string net_log_no_issuers_try_all_certs = "net_log_no_issuers_try_all_certs"; - internal const string net_log_server_issuers_look_for_matching_certs = "net_log_server_issuers_look_for_matching_certs"; - internal const string net_log_selected_cert = "net_log_selected_cert"; - internal const string net_log_n_certs_after_filtering = "net_log_n_certs_after_filtering"; - internal const string net_log_finding_matching_certs = "net_log_finding_matching_certs"; - internal const string net_log_using_cached_credential = "net_log_using_cached_credential"; - internal const string net_log_remote_cert_user_declared_valid = "net_log_remote_cert_user_declared_valid"; - internal const string net_log_remote_cert_user_declared_invalid = "net_log_remote_cert_user_declared_invalid"; - internal const string net_log_remote_cert_has_no_errors = "net_log_remote_cert_has_no_errors"; - internal const string net_log_remote_cert_has_errors = "net_log_remote_cert_has_errors"; - internal const string net_log_remote_cert_not_available = "net_log_remote_cert_not_available"; - internal const string net_log_remote_cert_name_mismatch = "net_log_remote_cert_name_mismatch"; - internal const string net_log_proxy_autodetect_script_location_parse_error = "net_log_proxy_autodetect_script_location_parse_error"; - internal const string net_log_proxy_autodetect_failed = "net_log_proxy_autodetect_failed"; - internal const string net_log_proxy_script_execution_error = "net_log_proxy_script_execution_error"; - internal const string net_log_proxy_script_download_compile_error = "net_log_proxy_script_download_compile_error"; - internal const string net_log_proxy_system_setting_update = "net_log_proxy_system_setting_update"; - internal const string net_log_proxy_update_due_to_ip_config_change = "net_log_proxy_update_due_to_ip_config_change"; - internal const string net_log_proxy_called_with_null_parameter = "net_log_proxy_called_with_null_parameter"; - internal const string net_log_proxy_called_with_invalid_parameter = "net_log_proxy_called_with_invalid_parameter"; - internal const string net_log_proxy_ras_supported = "net_log_proxy_ras_supported"; - internal const string net_log_proxy_ras_notsupported_exception = "net_log_proxy_ras_notsupported_exception"; - internal const string net_log_proxy_winhttp_cant_open_session = "net_log_proxy_winhttp_cant_open_session"; - internal const string net_log_proxy_winhttp_getproxy_failed = "net_log_proxy_winhttp_getproxy_failed"; - internal const string net_log_proxy_winhttp_timeout_error = "net_log_proxy_winhttp_timeout_error"; - internal const string net_log_digest_hash_algorithm_not_supported = "net_log_digest_hash_algorithm_not_supported"; - internal const string net_log_digest_qop_not_supported = "net_log_digest_qop_not_supported"; - internal const string net_log_digest_requires_nonce = "net_log_digest_requires_nonce"; - internal const string net_log_auth_invalid_challenge = "net_log_auth_invalid_challenge"; - internal const string net_log_unknown = "net_log_unknown"; - internal const string net_log_operation_returned_something = "net_log_operation_returned_something"; - internal const string net_log_operation_failed_with_error = "net_log_operation_failed_with_error"; - internal const string net_log_buffered_n_bytes = "net_log_buffered_n_bytes"; - internal const string net_log_method_equal = "net_log_method_equal"; - internal const string net_log_releasing_connection = "net_log_releasing_connection"; - internal const string net_log_unexpected_exception = "net_log_unexpected_exception"; - internal const string net_log_server_response_error_code = "net_log_server_response_error_code"; - internal const string net_log_resubmitting_request = "net_log_resubmitting_request"; - internal const string net_log_retrieving_localhost_exception = "net_log_retrieving_localhost_exception"; - internal const string net_log_resolved_servicepoint_may_not_be_remote_server = "net_log_resolved_servicepoint_may_not_be_remote_server"; - internal const string net_log_closed_idle = "net_log_closed_idle"; - internal const string net_log_received_status_line = "net_log_received_status_line"; - internal const string net_log_sending_headers = "net_log_sending_headers"; - internal const string net_log_received_headers = "net_log_received_headers"; - internal const string net_log_shell_expression_pattern_format_warning = "net_log_shell_expression_pattern_format_warning"; - internal const string net_log_exception_in_callback = "net_log_exception_in_callback"; - internal const string net_log_sending_command = "net_log_sending_command"; - internal const string net_log_received_response = "net_log_received_response"; - internal const string net_log_socket_connected = "net_log_socket_connected"; - internal const string net_log_socket_accepted = "net_log_socket_accepted"; - internal const string net_log_socket_not_logged_file = "net_log_socket_not_logged_file"; - internal const string net_log_socket_connect_dnsendpoint = "net_log_socket_connect_dnsendpoint"; - internal const string SSPIInvalidHandleType = "SSPIInvalidHandleType"; - - private static SR loader = null; - private ResourceManager resources; - - internal SR() - { - resources = new System.Resources.ResourceManager("System", this.GetType().Assembly); - } - - private static SR GetLoader() - { - if (loader == null) - { - SR sr = new SR(); - Interlocked.CompareExchange(ref loader, sr, null); - } - return loader; - } - - private static CultureInfo Culture - { - get { return null/*use ResourceManager default, CultureInfo.CurrentUICulture*/; } - } - - public static ResourceManager Resources - { - get - { - return GetLoader().resources; - } - } - - public static string GetString(string name, params object[] args) - { - SR sys = GetLoader(); - if (sys == null) - { - return null; - } - string res = sys.resources.GetString(name, SR.Culture); - - if (args != null && args.Length > 0) - { - for (int i = 0; i < args.Length; i++) - { - String value = args[i] as String; - if (value != null && value.Length > 1024) - { - args[i] = value.Substring(0, 1024 - 3) + "..."; - } - } - return String.Format(CultureInfo.CurrentCulture, res, args); - } - else - { - return res; - } - } - - public static string GetString(string name) - { - SR sys = GetLoader(); - if (sys == null) - { - return null; - } - return sys.resources.GetString(name, SR.Culture); - } - - public static string GetString(string name, out bool usedFallback) - { - // always false for this version of gensr - usedFallback = false; - return GetString(name); - } - - public static object GetObject(string name) - { - SR sys = GetLoader(); - if (sys == null) - { - return null; - } - return sys.resources.GetObject(name, SR.Culture); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs b/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs deleted file mode 100644 index 38628fd240..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Legacy/ValidationHelper.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace Microsoft.AspNet.Security.Windows -{ - using System; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.Net.Security; - using System.Runtime.InteropServices; - using System.Runtime.Versioning; - using System.Security.Authentication.ExtendedProtection; - using System.Security.Cryptography.X509Certificates; - using System.Security.Permissions; - - internal static class ValidationHelper - { - public static string ExceptionMessage(Exception exception) - { - if (exception == null) - { - return string.Empty; - } - if (exception.InnerException == null) - { - return exception.Message; - } - return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")"; - } - - public static string ToString(object objectValue) - { - if (objectValue == null) - { - return "(null)"; - } - else if (objectValue is string && ((string)objectValue).Length == 0) - { - return "(string.empty)"; - } - else if (objectValue is Exception) - { - return ExceptionMessage(objectValue as Exception); - } - else if (objectValue is IntPtr) - { - return "0x" + ((IntPtr)objectValue).ToString("x"); - } - else - { - return objectValue.ToString(); - } - } - public static string HashString(object objectValue) - { - if (objectValue == null) - { - return "(null)"; - } - else if (objectValue is string && ((string)objectValue).Length == 0) - { - return "(string.empty)"; - } - else - { - return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo); - } - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj b/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj deleted file mode 100644 index 5e97f1a4bf..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/Microsoft.AspNet.Security.Windows.kproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 12.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - efc7538f-7aeb-4a3e-a1e6-6bdccbd272bf - Library - net45 - - - - - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs b/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs deleted file mode 100644 index 32cca3646d..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NTAuthentication.cs +++ /dev/null @@ -1,738 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Net; -using System.Security.Authentication.ExtendedProtection; -using System.Security.Permissions; -using System.Security.Principal; -using System.Text; -using System.Threading; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class NTAuthentication - { - private static readonly ContextCallback Callback = new ContextCallback(InitializeCallback); - private static ISSPIInterface SSPIAuth = new SSPIAuthType(); - - private bool _isServer; - - private SafeFreeCredentials _credentialsHandle; - private SafeDeleteContext _securityContext; - private string _spn; - private string _clientSpecifiedSpn; - - private int _tokenSize; - private ContextFlags _requestedContextFlags; - private ContextFlags _contextFlags; - private string _uniqueUserId; - - private bool _isCompleted; - private string _protocolName; - private SecSizes _sizes; - private string _lastProtocolName; - private string _package; - - private ChannelBinding _channelBinding; - - // This overload does not attmept to impersonate because the caller either did it already or the original thread context is still preserved - - internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding) - { - Initialize(isServer, package, credential, spn, requestedContextFlags, channelBinding); - } - - // This overload always uses the default credentials for the process. - - [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)] - internal NTAuthentication(bool isServer, string package, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding) - { - try - { - using (WindowsIdentity.Impersonate(IntPtr.Zero)) - { - Initialize(isServer, package, CredentialCache.DefaultNetworkCredentials, spn, requestedContextFlags, channelBinding); - } - } - catch - { - // Avoid exception filter attacks. - throw; - } - } - - // The semantic of this propoerty is "Don't call me again". - // It can be completed either with success or error - // The latest case is signalled by IsValidContext==false - internal bool IsCompleted - { - get - { - return _isCompleted; - } - } - - internal bool IsValidContext - { - get - { - return !(_securityContext == null || _securityContext.IsInvalid); - } - } - - internal string AssociatedName - { - get - { - if (!(IsValidContext && IsCompleted)) - { - throw new Win32Exception((int)SecurityStatus.InvalidHandle); - } - - string name = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext, ContextAttribute.Names) as string; - GlobalLog.Print("NTAuthentication: The context is associated with [" + name + "]"); - return name; - } - } - - internal bool IsConfidentialityFlag - { - get - { - return (_contextFlags & ContextFlags.Confidentiality) != 0; - } - } - - internal bool IsIntegrityFlag - { - get - { - return (_contextFlags & (_isServer ? ContextFlags.AcceptIntegrity : ContextFlags.InitIntegrity)) != 0; - } - } - - internal bool IsMutualAuthFlag - { - get - { - return (_contextFlags & ContextFlags.MutualAuth) != 0; - } - } - - internal bool IsDelegationFlag - { - get - { - return (_contextFlags & ContextFlags.Delegate) != 0; - } - } - - internal bool IsIdentifyFlag - { - get - { - return (_contextFlags & (_isServer ? ContextFlags.AcceptIdentify : ContextFlags.InitIdentify)) != 0; - } - } - - internal string Spn - { - get - { - return _spn; - } - } - - internal string ClientSpecifiedSpn - { - get - { - if (_clientSpecifiedSpn == null) - { - _clientSpecifiedSpn = GetClientSpecifiedSpn(); - } - return _clientSpecifiedSpn; - } - } - - // True indicates this instance is for Server and will use AcceptSecurityContext SSPI API - - internal bool IsServer - { - get - { - return _isServer; - } - } - - internal bool IsKerberos - { - get - { - if (_lastProtocolName == null) - { - _lastProtocolName = ProtocolName; - } - - return (object)_lastProtocolName == (object)NegotiationInfoClass.Kerberos; - } - } - internal bool IsNTLM - { - get - { - if (_lastProtocolName == null) - { - _lastProtocolName = ProtocolName; - } - - return (object)_lastProtocolName == (object)NegotiationInfoClass.NTLM; - } - } - - internal string Package - { - get - { - return _package; - } - } - - internal string ProtocolName - { - get - { - // NB: May return string.Empty if the auth is not done yet or failed - if (_protocolName == null) - { - NegotiationInfoClass negotiationInfo = null; - - if (IsValidContext) - { - negotiationInfo = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext, ContextAttribute.NegotiationInfo) as NegotiationInfoClass; - if (IsCompleted) - { - if (negotiationInfo != null) - { - // cache it only when it's completed - _protocolName = negotiationInfo.AuthenticationPackage; - } - } - } - return negotiationInfo == null ? string.Empty : negotiationInfo.AuthenticationPackage; - } - return _protocolName; - } - } - - internal SecSizes Sizes - { - get - { - GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::MaxDataSize|The context is not completed or invalid.", ValidationHelper.HashString(this)); - if (_sizes == null) - { - _sizes = SSPIWrapper.QueryContextAttributes( - SSPIAuth, - _securityContext, - ContextAttribute.Sizes) as SecSizes; - } - return _sizes; - } - } - - internal ChannelBinding ChannelBinding - { - get { return _channelBinding; } - } - - private static void InitializeCallback(object state) - { - InitializeCallbackContext context = (InitializeCallbackContext)state; - context.ThisPtr.Initialize(context.IsServer, context.Package, context.Credential, context.Spn, context.RequestedContextFlags, context.ChannelBinding); - } - - private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding) - { - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor() package:" + ValidationHelper.ToString(package) + " spn:" + ValidationHelper.ToString(spn) + " flags :" + requestedContextFlags.ToString()); - _tokenSize = SSPIWrapper.GetVerifyPackageInfo(SSPIAuth, package, true).MaxToken; - _isServer = isServer; - _spn = spn; - _securityContext = null; - _requestedContextFlags = requestedContextFlags; - _package = package; - _channelBinding = channelBinding; - - GlobalLog.Print("Peer SPN-> '" + _spn + "'"); - - // check if we're using DefaultCredentials - - if (credential == CredentialCache.DefaultNetworkCredentials) - { - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using DefaultCredentials"); - _credentialsHandle = SSPIWrapper.AcquireDefaultCredential( - SSPIAuth, - package, - (_isServer ? CredentialUse.Inbound : CredentialUse.Outbound)); - _uniqueUserId = "/S"; // save off for unique connection marking ONLY used by HTTP client - } - else if (ComNetOS.IsWin7orLater) - { - unsafe - { - SafeSspiAuthDataHandle authData = null; - try - { - SecurityStatus result = UnsafeNclNativeMethods.SspiHelper.SspiEncodeStringsAsAuthIdentity( - credential.UserName/*InternalGetUserName()*/, credential.Domain/*InternalGetDomain()*/, - credential.Password/*InternalGetPassword()*/, out authData); - - if (result != SecurityStatus.OK) - { - if (Logging.On) - { - Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "SspiEncodeStringsAsAuthIdentity()", String.Format(CultureInfo.CurrentCulture, "0x{0:X}", (int)result))); - } - throw new Win32Exception((int)result); - } - - _credentialsHandle = SSPIWrapper.AcquireCredentialsHandle(SSPIAuth, - package, (_isServer ? CredentialUse.Inbound : CredentialUse.Outbound), ref authData); - } - finally - { - if (authData != null) - { - authData.Dispose(); - } - } - } - } - else - { - // we're not using DefaultCredentials, we need a - // AuthIdentity struct to contain credentials - // SECREVIEW: - // we'll save username/domain in temp strings, to avoid decrypting multiple times. - // password is only used once - - string username = credential.UserName; // InternalGetUserName(); - - string domain = credential.Domain; // InternalGetDomain(); - // ATTN: - // NetworkCredential class does not differentiate between null and "" but SSPI packages treat these cases differently - // For NTLM we want to keep "" for Wdigest.Dll we should use null. - AuthIdentity authIdentity = new AuthIdentity(username, credential.Password/*InternalGetPassword()*/, (object)package == (object)NegotiationInfoClass.WDigest && (domain == null || domain.Length == 0) ? null : domain); - - _uniqueUserId = domain + "/" + username + "/U"; // save off for unique connection marking ONLY used by HTTP client - - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using authIdentity:" + authIdentity.ToString()); - - _credentialsHandle = SSPIWrapper.AcquireCredentialsHandle( - SSPIAuth, - package, - (_isServer ? CredentialUse.Inbound : CredentialUse.Outbound), - ref authIdentity); - } - } - - // This will return an client token when conducted authentication on server side' - // This token can be used ofr impersanation - // We use it to create a WindowsIdentity and hand it out to the server app. - internal SafeCloseHandle GetContextToken(out SecurityStatus status) - { - GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", ValidationHelper.HashString(this)); - GlobalLog.Assert(IsServer, "NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", ValidationHelper.HashString(this)); - - if (!IsValidContext) - { - throw new Win32Exception((int)SecurityStatus.InvalidHandle); - } - - SafeCloseHandle token = null; - status = (SecurityStatus)SSPIWrapper.QuerySecurityContextToken( - SSPIAuth, - _securityContext, - out token); - - return token; - } - - internal SafeCloseHandle GetContextToken() - { - SecurityStatus status; - SafeCloseHandle token = GetContextToken(out status); - if (status != SecurityStatus.OK) - { - throw new Win32Exception((int)status); - } - return token; - } - - internal void CloseContext() - { - if (_securityContext != null && !_securityContext.IsClosed) - { - _securityContext.Dispose(); - } - } - - // NTAuth::GetOutgoingBlob() - // Created: 12-01-1999: L.M. - // Description: - // Accepts an incoming binary security blob and returns - // an outgoing binary security blob - internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatus statusCode) - { - GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes"); - - List list = new List(2); - - if (incomingBlob != null) - { - list.Add(new SecurityBuffer(incomingBlob, BufferType.Token)); - } - if (_channelBinding != null) - { - list.Add(new SecurityBuffer(_channelBinding)); - } - - SecurityBuffer[] inSecurityBufferArray = null; - if (list.Count > 0) - { - inSecurityBufferArray = list.ToArray(); - } - - SecurityBuffer outSecurityBuffer = new SecurityBuffer(_tokenSize, BufferType.Token); - - bool firstTime = _securityContext == null; - try - { - if (!_isServer) - { - // client session - statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext( - SSPIAuth, - _credentialsHandle, - ref _securityContext, - _spn, - _requestedContextFlags, - Endianness.Network, - inSecurityBufferArray, - outSecurityBuffer, - ref _contextFlags); - - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); - - if (statusCode == SecurityStatus.CompleteNeeded) - { - SecurityBuffer[] inSecurityBuffers = new SecurityBuffer[1]; - inSecurityBuffers[0] = outSecurityBuffer; - - statusCode = (SecurityStatus)SSPIWrapper.CompleteAuthToken( - SSPIAuth, - ref _securityContext, - inSecurityBuffers); - - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); - outSecurityBuffer.token = null; - } - } - else - { - // server session - statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext( - SSPIAuth, - _credentialsHandle, - ref _securityContext, - _requestedContextFlags, - Endianness.Network, - inSecurityBufferArray, - outSecurityBuffer, - ref _contextFlags); - - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); - } - } - finally - { - // Assuming the ISC or ASC has referenced the credential on the first successful call, - // we want to decrement the effective ref count by "disposing" it. - // The real dispose will happen when the security context is closed. - // Note if the first call was not successfull the handle is physically destroyed here - - if (firstTime && _credentialsHandle != null) - { - _credentialsHandle.Dispose(); - } - } - - if (((int)statusCode & unchecked((int)0x80000000)) != 0) - { - CloseContext(); - _isCompleted = true; - if (throwOnError) - { - Win32Exception exception = new Win32Exception((int)statusCode); - GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception); - throw exception; - } - GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); - return null; - } - else if (firstTime && _credentialsHandle != null) - { - // cache until it is pushed out by newly incoming handles - SSPIHandleCache.CacheCredential(_credentialsHandle); - } - - // the return value from SSPI will tell us correctly if the - // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm - // we also have to consider the case in which SSPI formed a new context, in this case we're done as well. - if (statusCode == SecurityStatus.OK) - { - // we're sucessfully done - GlobalLog.Assert(statusCode == SecurityStatus.OK, "NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", ValidationHelper.HashString(this), (int)statusCode, statusCode, ValidationHelper.HashString(_securityContext), ValidationHelper.ToString(_securityContext)); - _isCompleted = true; - } - else - { - // we need to continue - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(_securityContext) + "::Handle:" + ValidationHelper.ToString(_securityContext) + "]"); - } - // GlobalLog.Print("out token = " + outSecurityBuffer.ToString()); - // GlobalLog.Dump(outSecurityBuffer.token); - GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString()); - return outSecurityBuffer.token; - } - - // for Server side (IIS 6.0) see: \\netindex\Sources\inetsrv\iis\iisrearc\iisplus\ulw3\digestprovider.cxx - // for Client side (HTTP.SYS) see: \\netindex\Sources\net\http\sys\ucauth.c - internal string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, string requestedUri, string realm, bool isClientPreAuth, bool throwOnError, out SecurityStatus statusCode) - { - GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", incomingBlob); - - // second time call with 3 incoming buffers to select HTTP client. - // we should get back a SecurityStatus.OK and a non null outgoingBlob. - SecurityBuffer[] inSecurityBuffers = null; - SecurityBuffer outSecurityBuffer = new SecurityBuffer(_tokenSize, isClientPreAuth ? BufferType.Parameters : BufferType.Token); - - bool firstTime = _securityContext == null; - try - { - if (!_isServer) - { - // client session - - if (!isClientPreAuth) - { - if (incomingBlob != null) - { - List list = new List(5); - - list.Add(new SecurityBuffer(HeaderEncoding.GetBytes(incomingBlob), BufferType.Token)); - list.Add(new SecurityBuffer(HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters)); - list.Add(new SecurityBuffer(null, BufferType.Parameters)); - list.Add(new SecurityBuffer(Encoding.Unicode.GetBytes(_spn), BufferType.TargetHost)); - - if (_channelBinding != null) - { - list.Add(new SecurityBuffer(_channelBinding)); - } - - inSecurityBuffers = list.ToArray(); - } - - statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext( - SSPIAuth, - _credentialsHandle, - ref _securityContext, - requestedUri, // this must match the Uri in the HTTP status line for the current request - _requestedContextFlags, - Endianness.Network, - inSecurityBuffers, - outSecurityBuffer, - ref _contextFlags); - - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); - } - else - { -#if WDIGEST_PREAUTH - inSecurityBuffers = new SecurityBuffer[] { - new SecurityBuffer(null, BufferType.Token), - new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters), - new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters), - new SecurityBuffer(null, BufferType.Parameters), - outSecurityBuffer, - }; - - statusCode = (SecurityStatus) SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, m_SecurityContext, inSecurityBuffers, 0); - - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.MakeSignature() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); -#else - statusCode = SecurityStatus.OK; - GlobalLog.Assert("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob()", "Invalid code path."); -#endif - } - } - else - { - // server session - List list = new List(6); - - list.Add(incomingBlob == null ? new SecurityBuffer(0, BufferType.Token) : new SecurityBuffer(HeaderEncoding.GetBytes(incomingBlob), BufferType.Token)); - list.Add(requestMethod == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters)); - list.Add(requestedUri == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters)); - list.Add(new SecurityBuffer(0, BufferType.Parameters)); - list.Add(realm == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(Encoding.Unicode.GetBytes(realm), BufferType.Parameters)); - - if (_channelBinding != null) - { - list.Add(new SecurityBuffer(_channelBinding)); - } - - inSecurityBuffers = list.ToArray(); - - statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext( - SSPIAuth, - _credentialsHandle, - ref _securityContext, - _requestedContextFlags, - Endianness.Network, - inSecurityBuffers, - outSecurityBuffer, - ref _contextFlags); - - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); - - if (statusCode == SecurityStatus.CompleteNeeded) - { - inSecurityBuffers[4] = outSecurityBuffer; - - statusCode = (SecurityStatus)SSPIWrapper.CompleteAuthToken( - SSPIAuth, - ref _securityContext, - inSecurityBuffers); - - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); - - outSecurityBuffer.token = null; - } - } - } - finally - { - // Assuming the ISC or ASC has referenced the credential on the first successful call, - // we want to decrement the effective ref count by "disposing" it. - // The real dispose will happen when the security context is closed. - // Note if the first call was not successfull the handle is physically destroyed here - - if (firstTime && _credentialsHandle != null) - { - _credentialsHandle.Dispose(); - } - } - - if (((int)statusCode & unchecked((int)0x80000000)) != 0) - { - CloseContext(); - if (throwOnError) - { - Win32Exception exception = new Win32Exception((int)statusCode); - GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "Win32Exception:" + exception); - throw exception; - } - GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "null statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); - return null; - } - else if (firstTime && _credentialsHandle != null) - { - // cache until it is pushed out by newly incoming handles - SSPIHandleCache.CacheCredential(_credentialsHandle); - } - - // the return value from SSPI will tell us correctly if the - // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm - if (statusCode == SecurityStatus.OK) - { - // we're done, cleanup - _isCompleted = true; - } - else - { - // we need to continue - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() need continue statusCode:[0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(_securityContext) + "::Handle:" + ValidationHelper.ToString(_securityContext) + "]"); - } - GlobalLog.Print("out token = " + outSecurityBuffer.ToString()); - GlobalLog.Dump(outSecurityBuffer.token); - GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() IsCompleted:" + IsCompleted.ToString()); - - byte[] decodedOutgoingBlob = outSecurityBuffer.token; - string outgoingBlob = null; - if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) - { - outgoingBlob = HeaderEncoding.GetString(decodedOutgoingBlob, 0, outSecurityBuffer.size); - } - GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", outgoingBlob); - return outgoingBlob; - } - - private string GetClientSpecifiedSpn() - { - GlobalLog.Assert(IsValidContext && IsCompleted, "NTAuthentication: Trying to get the client SPN before handshaking is done!"); - - string spn = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext, - ContextAttribute.ClientSpecifiedSpn) as string; - - GlobalLog.Print("NTAuthentication: The client specified SPN is [" + spn + "]"); - return spn; - } - - private class InitializeCallbackContext - { - internal readonly NTAuthentication ThisPtr; - internal readonly bool IsServer; - internal readonly string Package; - internal readonly NetworkCredential Credential; - internal readonly string Spn; - internal readonly ContextFlags RequestedContextFlags; - internal readonly ChannelBinding ChannelBinding; - - internal InitializeCallbackContext(NTAuthentication thisPtr, bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding) - { - this.ThisPtr = thisPtr; - this.IsServer = isServer; - this.Package = package; - this.Credential = credential; - this.Spn = spn; - this.RequestedContextFlags = requestedContextFlags; - this.ChannelBinding = channelBinding; - } - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs deleted file mode 100644 index 37f9b57c78..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/AuthIdentity.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - internal struct AuthIdentity - { - // see SEC_WINNT_AUTH_IDENTITY_W - internal string UserName; - internal int UserNameLength; - internal string Domain; - internal int DomainLength; - internal string Password; - internal int PasswordLength; - internal int Flags; - - internal AuthIdentity(string userName, string password, string domain) - { - UserName = userName; - UserNameLength = userName == null ? 0 : userName.Length; - Password = password; - PasswordLength = password == null ? 0 : password.Length; - Domain = domain; - DomainLength = domain == null ? 0 : domain.Length; - // Flags are 2 for Unicode and 1 for ANSI. We use 2 on NT and 1 on Win9x. - Flags = 2; - } - - public override string ToString() - { - return ValidationHelper.ToString(Domain) + "\\" + ValidationHelper.ToString(UserName); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs deleted file mode 100644 index c9595a2f60..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/ContextFlags.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; - -namespace Microsoft.AspNet.Security.Windows -{ - // #define ISC_REQ_DELEGATE 0x00000001 - // #define ISC_REQ_MUTUAL_AUTH 0x00000002 - // #define ISC_REQ_REPLAY_DETECT 0x00000004 - // #define ISC_REQ_SEQUENCE_DETECT 0x00000008 - // #define ISC_REQ_CONFIDENTIALITY 0x00000010 - // #define ISC_REQ_USE_SESSION_KEY 0x00000020 - // #define ISC_REQ_PROMPT_FOR_CREDS 0x00000040 - // #define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080 - // #define ISC_REQ_ALLOCATE_MEMORY 0x00000100 - // #define ISC_REQ_USE_DCE_STYLE 0x00000200 - // #define ISC_REQ_DATAGRAM 0x00000400 - // #define ISC_REQ_CONNECTION 0x00000800 - // #define ISC_REQ_CALL_LEVEL 0x00001000 - // #define ISC_REQ_FRAGMENT_SUPPLIED 0x00002000 - // #define ISC_REQ_EXTENDED_ERROR 0x00004000 - // #define ISC_REQ_STREAM 0x00008000 - // #define ISC_REQ_INTEGRITY 0x00010000 - // #define ISC_REQ_IDENTIFY 0x00020000 - // #define ISC_REQ_NULL_SESSION 0x00040000 - // #define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000 - // #define ISC_REQ_RESERVED1 0x00100000 - // #define ISC_REQ_FRAGMENT_TO_FIT 0x00200000 - // #define ISC_REQ_HTTP 0x10000000 - // Win7 SP1 + - // #define ISC_REQ_UNVERIFIED_TARGET_NAME 0x20000000 - - // #define ASC_REQ_DELEGATE 0x00000001 - // #define ASC_REQ_MUTUAL_AUTH 0x00000002 - // #define ASC_REQ_REPLAY_DETECT 0x00000004 - // #define ASC_REQ_SEQUENCE_DETECT 0x00000008 - // #define ASC_REQ_CONFIDENTIALITY 0x00000010 - // #define ASC_REQ_USE_SESSION_KEY 0x00000020 - // #define ASC_REQ_ALLOCATE_MEMORY 0x00000100 - // #define ASC_REQ_USE_DCE_STYLE 0x00000200 - // #define ASC_REQ_DATAGRAM 0x00000400 - // #define ASC_REQ_CONNECTION 0x00000800 - // #define ASC_REQ_CALL_LEVEL 0x00001000 - // #define ASC_REQ_EXTENDED_ERROR 0x00008000 - // #define ASC_REQ_STREAM 0x00010000 - // #define ASC_REQ_INTEGRITY 0x00020000 - // #define ASC_REQ_LICENSING 0x00040000 - // #define ASC_REQ_IDENTIFY 0x00080000 - // #define ASC_REQ_ALLOW_NULL_SESSION 0x00100000 - // #define ASC_REQ_ALLOW_NON_USER_LOGONS 0x00200000 - // #define ASC_REQ_ALLOW_CONTEXT_REPLAY 0x00400000 - // #define ASC_REQ_FRAGMENT_TO_FIT 0x00800000 - // #define ASC_REQ_FRAGMENT_SUPPLIED 0x00002000 - // #define ASC_REQ_NO_TOKEN 0x01000000 - // #define ASC_REQ_HTTP 0x10000000 - - [Flags] - internal enum ContextFlags - { - Zero = 0, - // The server in the transport application can - // build new security contexts impersonating the - // client that will be accepted by other servers - // as the client's contexts. - Delegate = 0x00000001, - // The communicating parties must authenticate - // their identities to each other. Without MutualAuth, - // the client authenticates its identity to the server. - // With MutualAuth, the server also must authenticate - // its identity to the client. - MutualAuth = 0x00000002, - // The security package detects replayed packets and - // notifies the caller if a packet has been replayed. - // The use of this flag implies all of the conditions - // specified by the Integrity flag. - ReplayDetect = 0x00000004, - // The context must be allowed to detect out-of-order - // delivery of packets later through the message support - // functions. Use of this flag implies all of the - // conditions specified by the Integrity flag. - SequenceDetect = 0x00000008, - // The context must protect data while in transit. - // Confidentiality is supported for NTLM with Microsoft - // Windows NT version 4.0, SP4 and later and with the - // Kerberos protocol in Microsoft Windows 2000 and later. - Confidentiality = 0x00000010, - UseSessionKey = 0x00000020, - AllocateMemory = 0x00000100, - - // Connection semantics must be used. - Connection = 0x00000800, - - // Client applications requiring extended error messages specify the - // ISC_REQ_EXTENDED_ERROR flag when calling the InitializeSecurityContext - // Server applications requiring extended error messages set - // the ASC_REQ_EXTENDED_ERROR flag when calling AcceptSecurityContext. - InitExtendedError = 0x00004000, - AcceptExtendedError = 0x00008000, - // A transport application requests stream semantics - // by setting the ISC_REQ_STREAM and ASC_REQ_STREAM - // flags in the calls to the InitializeSecurityContext - // and AcceptSecurityContext functions - InitStream = 0x00008000, - AcceptStream = 0x00010000, - // Buffer integrity can be verified; however, replayed - // and out-of-sequence messages will not be detected - InitIntegrity = 0x00010000, // ISC_REQ_INTEGRITY - AcceptIntegrity = 0x00020000, // ASC_REQ_INTEGRITY - - InitManualCredValidation = 0x00080000, // ISC_REQ_MANUAL_CRED_VALIDATION - InitUseSuppliedCreds = 0x00000080, // ISC_REQ_USE_SUPPLIED_CREDS - InitIdentify = 0x00020000, // ISC_REQ_IDENTIFY - AcceptIdentify = 0x00080000, // ASC_REQ_IDENTIFY - - ProxyBindings = 0x04000000, // ASC_REQ_PROXY_BINDINGS - AllowMissingBindings = 0x10000000, // ASC_REQ_ALLOW_MISSING_BINDINGS - - UnverifiedTargetName = 0x20000000, // ISC_REQ_UNVERIFIED_TARGET_NAME - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs deleted file mode 100644 index e5613203f9..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/NativeSSPI.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Globalization; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - // used to define the interface for security to use. - internal interface ISSPIInterface - { - SecurityPackageInfoClass[] SecurityPackages { get; set; } - int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray); - int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref AuthIdentity authdata, out SafeFreeCredentials outCredential); - int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential); - int AcquireDefaultCredential(string moduleName, CredentialUse usage, out SafeFreeCredentials outCredential); - int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref SecureCredential authdata, out SafeFreeCredentials outCredential); - int AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, ContextFlags inFlags, - Endianness endianness, SecurityBuffer outputBuffer, ref ContextFlags outFlags); - int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, ContextFlags inFlags, - Endianness endianness, SecurityBuffer outputBuffer, ref ContextFlags outFlags); - int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, - Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlags outFlags); - int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, - Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags); - int EncryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber); - int DecryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber); - int MakeSignature(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber); - int VerifySignature(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber); - - int QueryContextChannelBinding(SafeDeleteContext phContext, ContextAttribute attribute, out SafeFreeContextBufferChannelBinding refHandle); - int QueryContextAttributes(SafeDeleteContext phContext, ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle); - int SetContextAttributes(SafeDeleteContext phContext, ContextAttribute attribute, byte[] buffer); - int QuerySecurityContextToken(SafeDeleteContext phContext, out SafeCloseHandle phToken); - int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers); - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs deleted file mode 100644 index 5bd541ba73..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIAuthType.cs +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Globalization; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class SSPIAuthType : ISSPIInterface - { - private static volatile SecurityPackageInfoClass[] _securityPackages; - - public SecurityPackageInfoClass[] SecurityPackages - { - get - { - return _securityPackages; - } - set - { - _securityPackages = value; - } - } - - public int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray) - { - GlobalLog.Print("SSPIAuthType::EnumerateSecurityPackages()"); - return SafeFreeContextBuffer.EnumeratePackages(out pkgnum, out pkgArray); - } - - public int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref AuthIdentity authdata, out SafeFreeCredentials outCredential) - { - return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); - } - - public int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential) - { - return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); - } - - public int AcquireDefaultCredential(string moduleName, CredentialUse usage, out SafeFreeCredentials outCredential) - { - return SafeFreeCredentials.AcquireDefaultCredential(moduleName, usage, out outCredential); - } - - public int AcquireCredentialsHandle(string moduleName, CredentialUse usage, ref SecureCredential authdata, out SafeFreeCredentials outCredential) - { - return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential); - } - - public int AcceptSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer inputBuffer, ContextFlags inFlags, Endianness endianness, SecurityBuffer outputBuffer, ref ContextFlags outFlags) - { - return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags); - } - - public int AcceptSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers, ContextFlags inFlags, Endianness endianness, SecurityBuffer outputBuffer, ref ContextFlags outFlags) - { - return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags); - } - - public int InitializeSecurityContext(ref SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlags outFlags) - { - return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, inputBuffer, null, outputBuffer, ref outFlags); - } - - public int InitializeSecurityContext(SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags) - { - return SafeDeleteContext.InitializeSecurityContext(ref credential, ref context, targetName, inFlags, endianness, null, inputBuffers, outputBuffer, ref outFlags); - } - - public int EncryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) - { - int status = (int)SecurityStatus.InvalidHandle; - bool b = false; - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - context.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - context.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - status = UnsafeNclNativeMethods.NativeNTSSPI.EncryptMessage(ref context._handle, 0, inputOutput, sequenceNumber); - context.DangerousRelease(); - } - } - return status; - } - - public unsafe int DecryptMessage(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) - { - int status = (int)SecurityStatus.InvalidHandle; - bool b = false; - uint qop = 0; - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - context.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - context.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - status = UnsafeNclNativeMethods.NativeNTSSPI.DecryptMessage(ref context._handle, inputOutput, sequenceNumber, &qop); - context.DangerousRelease(); - } - } - - const uint SECQOP_WRAP_NO_ENCRYPT = 0x80000001; - if (status == 0 && qop == SECQOP_WRAP_NO_ENCRYPT) - { - GlobalLog.Assert("NativeNTSSPI.DecryptMessage", "Expected qop = 0, returned value = " + qop.ToString("x", CultureInfo.InvariantCulture)); - throw new InvalidOperationException(SR.GetString(SR.net_auth_message_not_encrypted)); - } - - return status; - } - - public int MakeSignature(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) - { - int status = (int)SecurityStatus.InvalidHandle; - bool b = false; - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - context.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - context.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - const uint SECQOP_WRAP_NO_ENCRYPT = 0x80000001; - status = UnsafeNclNativeMethods.NativeNTSSPI.EncryptMessage(ref context._handle, SECQOP_WRAP_NO_ENCRYPT, inputOutput, sequenceNumber); - context.DangerousRelease(); - } - } - return status; - } - - public unsafe int VerifySignature(SafeDeleteContext context, SecurityBufferDescriptor inputOutput, uint sequenceNumber) - { - int status = (int)SecurityStatus.InvalidHandle; - bool b = false; - - uint qop = 0; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - context.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - context.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - status = UnsafeNclNativeMethods.NativeNTSSPI.DecryptMessage(ref context._handle, inputOutput, sequenceNumber, &qop); - context.DangerousRelease(); - } - } - - return status; - } - - public int QueryContextChannelBinding(SafeDeleteContext context, ContextAttribute attribute, out SafeFreeContextBufferChannelBinding binding) - { - // Querying an auth SSP for a CBT doesn't make sense - binding = null; - throw new NotSupportedException(); - } - - public unsafe int QueryContextAttributes(SafeDeleteContext context, ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle) - { - refHandle = null; - if (handleType != null) - { - if (handleType == typeof(SafeFreeContextBuffer)) - { - refHandle = SafeFreeContextBuffer.CreateEmptyHandle(); - } - else if (handleType == typeof(SafeFreeCertContext)) - { - refHandle = new SafeFreeCertContext(); - } - else - { - throw new ArgumentException(SR.GetString(SR.SSPIInvalidHandleType, handleType.FullName), "handleType"); - } - } - - fixed (byte* bufferPtr = buffer) - { - return SafeFreeContextBuffer.QueryContextAttributes(context, attribute, bufferPtr, refHandle); - } - } - - public int SetContextAttributes(SafeDeleteContext context, ContextAttribute attribute, byte[] buffer) - { - throw new NotImplementedException(); - } - - public int QuerySecurityContextToken(SafeDeleteContext phContext, out SafeCloseHandle phToken) - { - return GetSecurityContextToken(phContext, out phToken); - } - - public int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers) - { - return SafeDeleteContext.CompleteAuthToken(ref refContext, inputBuffers); - } - - private static int GetSecurityContextToken(SafeDeleteContext phContext, out SafeCloseHandle safeHandle) - { - int status = (int)SecurityStatus.InvalidHandle; - bool b = false; - safeHandle = null; - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - phContext.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - phContext.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - status = UnsafeNclNativeMethods.SafeNetHandles.QuerySecurityContextToken(ref phContext._handle, out safeHandle); - phContext.DangerousRelease(); - } - } - - return status; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs deleted file mode 100644 index 5faa836bf6..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIHandle.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.ConstrainedExecution; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct SSPIHandle - { - private IntPtr HandleHi; - private IntPtr HandleLo; - - public bool IsZero - { - get { return HandleHi == IntPtr.Zero && HandleLo == IntPtr.Zero; } - } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal void SetToInvalid() - { - HandleHi = IntPtr.Zero; - HandleLo = IntPtr.Zero; - } - - public override string ToString() - { - return HandleHi.ToString("x") + ":" + HandleLo.ToString("x"); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs deleted file mode 100644 index bc7b3da731..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPISessionCache.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -/* -Abstract: - The file implements trivial SSPI credential caching mechanism based on lru list -*/ -using System; -using System.Threading; - -namespace Microsoft.AspNet.Security.Windows -{ - // Implements delayed SSPI handle release, like a finalizable object though the handles are kept alive until being pushed out - // by the newly incoming ones. - internal static class SSPIHandleCache - { - private const int MaxCacheSize = 0x1F; // must a (power of 2) - 1 - private static SafeCredentialReference[] _cacheSlots = new SafeCredentialReference[MaxCacheSize + 1]; - private static int _current = -1; - - internal static void CacheCredential(SafeFreeCredentials newHandle) - { - try - { - SafeCredentialReference newRef = SafeCredentialReference.CreateReference(newHandle); - if (newRef == null) - { - return; - } - unchecked - { - int index = Interlocked.Increment(ref _current) & MaxCacheSize; - newRef = Interlocked.Exchange(ref _cacheSlots[index], newRef); - } - if (newRef != null) - { - newRef.Dispose(); - } - } - catch (Exception e) - { - GlobalLog.Assert("SSPIHandlCache", "Attempted to throw: " + e.ToString()); - } - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs deleted file mode 100644 index 5ac2fbc861..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SSPIWrapper.cs +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - // From Schannel.h - - [StructLayout(LayoutKind.Sequential)] - internal struct NegotiationInfo - { - // see SecPkgContext_NegotiationInfoW in - - // [MarshalAs(UnmanagedType.LPStruct)] internal SecurityPackageInfo PackageInfo; - internal IntPtr PackageInfo; - internal uint NegotiationState; - internal static readonly int Size = Marshal.SizeOf(typeof(NegotiationInfo)); - internal static readonly int NegotiationStateOffest = (int)Marshal.OffsetOf(typeof(NegotiationInfo), "NegotiationState"); - } - - // we keep it simple since we use this only to know if NTLM or - // Kerberos are used in the context of a Negotiate handshake - - [StructLayout(LayoutKind.Sequential)] - internal struct SecurityPackageInfo - { - // see SecPkgInfoW in - internal int Capabilities; - internal short Version; - internal short RPCID; - internal int MaxToken; - internal IntPtr Name; - internal IntPtr Comment; - - internal static readonly int Size = Marshal.SizeOf(typeof(SecurityPackageInfo)); - internal static readonly int NameOffest = (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Name"); - } - - [StructLayout(LayoutKind.Sequential)] - internal struct Bindings - { - // see SecPkgContext_Bindings in - internal int BindingsLength; - internal IntPtr pBindings; - } - - internal static class SSPIWrapper - { - internal static SecurityPackageInfoClass[] EnumerateSecurityPackages(ISSPIInterface secModule) - { - GlobalLog.Enter("EnumerateSecurityPackages"); - if (secModule.SecurityPackages == null) - { - lock (secModule) - { - if (secModule.SecurityPackages == null) - { - int moduleCount = 0; - SafeFreeContextBuffer arrayBaseHandle = null; - try - { - int errorCode = secModule.EnumerateSecurityPackages(out moduleCount, out arrayBaseHandle); - GlobalLog.Print("SSPIWrapper::arrayBase: " + (arrayBaseHandle.DangerousGetHandle().ToString("x"))); - if (errorCode != 0) - { - throw new Win32Exception(errorCode); - } - SecurityPackageInfoClass[] securityPackages = new SecurityPackageInfoClass[moduleCount]; - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_sspi_enumerating_security_packages)); - } - int i; - for (i = 0; i < moduleCount; i++) - { - securityPackages[i] = new SecurityPackageInfoClass(arrayBaseHandle, i); - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, " " + securityPackages[i].Name); - } - } - secModule.SecurityPackages = securityPackages; - } - finally - { - if (arrayBaseHandle != null) - { - arrayBaseHandle.Dispose(); - } - } - } - } - } - GlobalLog.Leave("EnumerateSecurityPackages"); - return secModule.SecurityPackages; - } - - internal static SecurityPackageInfoClass GetVerifyPackageInfo(ISSPIInterface secModule, string packageName, bool throwIfMissing) - { - SecurityPackageInfoClass[] supportedSecurityPackages = EnumerateSecurityPackages(secModule); - if (supportedSecurityPackages != null) - { - for (int i = 0; i < supportedSecurityPackages.Length; i++) - { - if (string.Compare(supportedSecurityPackages[i].Name, packageName, StringComparison.OrdinalIgnoreCase) == 0) - { - return supportedSecurityPackages[i]; - } - } - } - - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_sspi_security_package_not_found, packageName)); - } - - // error - if (throwIfMissing) - { - throw new NotSupportedException(SR.GetString(SR.net_securitypackagesupport)); - } - - return null; - } - - public static SafeFreeCredentials AcquireDefaultCredential(ISSPIInterface secModule, string package, CredentialUse intent) - { - GlobalLog.Print("SSPIWrapper::AcquireDefaultCredential(): using " + package); - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, - "AcquireDefaultCredential(" + - "package = " + package + ", " + - "intent = " + intent + ")"); - } - - SafeFreeCredentials outCredential = null; - int errorCode = secModule.AcquireDefaultCredential(package, intent, out outCredential); - - if (errorCode != 0) - { -#if TRAVE - GlobalLog.Print("SSPIWrapper::AcquireDefaultCredential(): error " + SecureChannel.MapSecurityStatus((uint)errorCode)); -#endif - if (Logging.On) - { - Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "AcquireDefaultCredential()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); - } - throw new Win32Exception(errorCode); - } - return outCredential; - } - - public static SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface secModule, string package, CredentialUse intent, ref AuthIdentity authdata) - { - GlobalLog.Print("SSPIWrapper::AcquireCredentialsHandle#2(): using " + package); - - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, - "AcquireCredentialsHandle(" + - "package = " + package + ", " + - "intent = " + intent + ", " + - "authdata = " + authdata + ")"); - } - - SafeFreeCredentials credentialsHandle = null; - int errorCode = secModule.AcquireCredentialsHandle(package, - intent, - ref authdata, - out credentialsHandle); - - if (errorCode != 0) - { - if (Logging.On) - { - Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "AcquireCredentialsHandle()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); - } - throw new Win32Exception(errorCode); - } - return credentialsHandle; - } - - public static SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface secModule, string package, CredentialUse intent, ref SafeSspiAuthDataHandle authdata) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, - "AcquireCredentialsHandle(" + - "package = " + package + ", " + - "intent = " + intent + ", " + - "authdata = " + authdata + ")"); - } - - SafeFreeCredentials credentialsHandle = null; - int errorCode = secModule.AcquireCredentialsHandle(package, intent, ref authdata, out credentialsHandle); - - if (errorCode != 0) - { - if (Logging.On) - { - Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "AcquireCredentialsHandle()", String.Format(CultureInfo.CurrentCulture, "0X{0:X}", errorCode))); - } - throw new Win32Exception(errorCode); - } - return credentialsHandle; - } - - internal static int InitializeSecurityContext(ISSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, string targetName, ContextFlags inFlags, Endianness datarep, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, - "InitializeSecurityContext(" + - "credential = " + credential.ToString() + ", " + - "context = " + ValidationHelper.ToString(context) + ", " + - "targetName = " + targetName + ", " + - "inFlags = " + inFlags + ")"); - } - - int errorCode = secModule.InitializeSecurityContext(credential, ref context, targetName, inFlags, datarep, inputBuffers, outputBuffer, ref outFlags); - - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_sspi_security_context_input_buffers, "InitializeSecurityContext", (inputBuffers == null ? 0 : inputBuffers.Length), outputBuffer.size, (SecurityStatus)errorCode)); - } - - return errorCode; - } - - internal static int AcceptSecurityContext(ISSPIInterface secModule, SafeFreeCredentials credential, ref SafeDeleteContext context, ContextFlags inFlags, Endianness datarep, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, - "AcceptSecurityContext(" + - "credential = " + credential.ToString() + ", " + - "context = " + ValidationHelper.ToString(context) + ", " + - "inFlags = " + inFlags + ")"); - } - - int errorCode = secModule.AcceptSecurityContext(credential, ref context, inputBuffers, inFlags, datarep, outputBuffer, ref outFlags); - - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_sspi_security_context_input_buffers, "AcceptSecurityContext", (inputBuffers == null ? 0 : inputBuffers.Length), outputBuffer.size, (SecurityStatus)errorCode)); - } - - return errorCode; - } - - internal static int CompleteAuthToken(ISSPIInterface secModule, ref SafeDeleteContext context, SecurityBuffer[] inputBuffers) - { - int errorCode = secModule.CompleteAuthToken(ref context, inputBuffers); - - if (Logging.On) - { - Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_operation_returned_something, "CompleteAuthToken()", (SecurityStatus)errorCode)); - } - - return errorCode; - } - - public static int QuerySecurityContextToken(ISSPIInterface secModule, SafeDeleteContext context, out SafeCloseHandle token) - { - return secModule.QuerySecurityContextToken(context, out token); - } - - public static SafeFreeContextBufferChannelBinding QueryContextChannelBinding(ISSPIInterface secModule, SafeDeleteContext securityContext, ContextAttribute contextAttribute) - { - GlobalLog.Enter("QueryContextChannelBinding", contextAttribute.ToString()); - - SafeFreeContextBufferChannelBinding result; - int errorCode = secModule.QueryContextChannelBinding(securityContext, contextAttribute, out result); - if (errorCode != 0) - { - GlobalLog.Leave("QueryContextChannelBinding", "ERROR = " + ErrorDescription(errorCode)); - return null; - } - - GlobalLog.Leave("QueryContextChannelBinding", ValidationHelper.HashString(result)); - return result; - } - - public static object QueryContextAttributes(ISSPIInterface secModule, SafeDeleteContext securityContext, ContextAttribute contextAttribute) - { - int errorCode; - return QueryContextAttributes(secModule, securityContext, contextAttribute, out errorCode); - } - - public static object QueryContextAttributes(ISSPIInterface secModule, SafeDeleteContext securityContext, ContextAttribute contextAttribute, out int errorCode) - { - GlobalLog.Enter("QueryContextAttributes", contextAttribute.ToString()); - - int nativeBlockSize = IntPtr.Size; - Type handleType = null; - - switch (contextAttribute) - { - case ContextAttribute.Sizes: - nativeBlockSize = SecSizes.SizeOf; - break; - case ContextAttribute.StreamSizes: - nativeBlockSize = StreamSizes.SizeOf; - break; - - case ContextAttribute.Names: - handleType = typeof(SafeFreeContextBuffer); - break; - - case ContextAttribute.PackageInfo: - handleType = typeof(SafeFreeContextBuffer); - break; - - case ContextAttribute.NegotiationInfo: - handleType = typeof(SafeFreeContextBuffer); - nativeBlockSize = Marshal.SizeOf(typeof(NegotiationInfo)); - break; - - case ContextAttribute.ClientSpecifiedSpn: - handleType = typeof(SafeFreeContextBuffer); - break; - - case ContextAttribute.RemoteCertificate: - handleType = typeof(SafeFreeCertContext); - break; - - case ContextAttribute.LocalCertificate: - handleType = typeof(SafeFreeCertContext); - break; - - case ContextAttribute.IssuerListInfoEx: - nativeBlockSize = Marshal.SizeOf(typeof(IssuerListInfoEx)); - handleType = typeof(SafeFreeContextBuffer); - break; - - case ContextAttribute.ConnectionInfo: - nativeBlockSize = Marshal.SizeOf(typeof(SslConnectionInfo)); - break; - - default: - throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "ContextAttribute"), "contextAttribute"); - } - - SafeHandle SspiHandle = null; - object attribute = null; - - try - { - byte[] nativeBuffer = new byte[nativeBlockSize]; - errorCode = secModule.QueryContextAttributes(securityContext, contextAttribute, nativeBuffer, handleType, out SspiHandle); - if (errorCode != 0) - { - GlobalLog.Leave("Win32:QueryContextAttributes", "ERROR = " + ErrorDescription(errorCode)); - return null; - } - - switch (contextAttribute) - { - case ContextAttribute.Sizes: - attribute = new SecSizes(nativeBuffer); - break; - - case ContextAttribute.StreamSizes: - attribute = new StreamSizes(nativeBuffer); - break; - - case ContextAttribute.Names: - attribute = Marshal.PtrToStringUni(SspiHandle.DangerousGetHandle()); - break; - - case ContextAttribute.PackageInfo: - attribute = new SecurityPackageInfoClass(SspiHandle, 0); - break; - - case ContextAttribute.NegotiationInfo: - unsafe - { - fixed (void* ptr = nativeBuffer) - { - attribute = new NegotiationInfoClass(SspiHandle, Marshal.ReadInt32(new IntPtr(ptr), NegotiationInfo.NegotiationStateOffest)); - } - } - break; - - case ContextAttribute.ClientSpecifiedSpn: - attribute = Marshal.PtrToStringUni(SspiHandle.DangerousGetHandle()); - break; - - case ContextAttribute.LocalCertificate: - goto case ContextAttribute.RemoteCertificate; - case ContextAttribute.RemoteCertificate: - attribute = SspiHandle; - SspiHandle = null; - break; - - case ContextAttribute.IssuerListInfoEx: - attribute = new IssuerListInfoEx(SspiHandle, nativeBuffer); - SspiHandle = null; - break; - - case ContextAttribute.ConnectionInfo: - attribute = new SslConnectionInfo(nativeBuffer); - break; - default: - // will return null - break; - } - } - finally - { - if (SspiHandle != null) - { - SspiHandle.Dispose(); - } - } - GlobalLog.Leave("QueryContextAttributes", ValidationHelper.ToString(attribute)); - return attribute; - } - - public static string ErrorDescription(int errorCode) - { - if (errorCode == -1) - { - return "An exception when invoking Win32 API"; - } - switch ((SecurityStatus)errorCode) - { - case SecurityStatus.InvalidHandle: - return "Invalid handle"; - case SecurityStatus.InvalidToken: - return "Invalid token"; - case SecurityStatus.ContinueNeeded: - return "Continue needed"; - case SecurityStatus.IncompleteMessage: - return "Message incomplete"; - case SecurityStatus.WrongPrincipal: - return "Wrong principal"; - case SecurityStatus.TargetUnknown: - return "Target unknown"; - case SecurityStatus.PackageNotFound: - return "Package not found"; - case SecurityStatus.BufferNotEnough: - return "Buffer not enough"; - case SecurityStatus.MessageAltered: - return "Message altered"; - case SecurityStatus.UntrustedRoot: - return "Untrusted root"; - default: - return "0x" + errorCode.ToString("x", NumberFormatInfo.InvariantInfo); - } - } - } // class SSPIWrapper -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs deleted file mode 100644 index 60455aa1da..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCloseHandle.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.ConstrainedExecution; -using System.Security; -using System.Threading; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.AspNet.Security.Windows -{ - [SuppressUnmanagedCodeSecurity] - internal sealed class SafeCloseHandle : CriticalHandleZeroOrMinusOneIsInvalid - { - private int _disposed; - - private SafeCloseHandle() - : base() - { - } - - internal IntPtr DangerousGetHandle() - { - return handle; - } - - protected override bool ReleaseHandle() - { - if (!IsInvalid) - { - if (Interlocked.Increment(ref _disposed) == 1) - { - return UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(handle); - } - } - return true; - } - - // This method will bypass refCount check done by VM - // Means it will force handle release if has a valid value - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal void Abort() - { - ReleaseHandle(); - SetHandleAsInvalid(); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs deleted file mode 100644 index 03428e4c5a..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeCredentialReference.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.CompilerServices; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.AspNet.Security.Windows -{ - internal sealed class SafeCredentialReference : CriticalHandleMinusOneIsInvalid - { - // Static cache will return the target handle if found the reference in the table. - internal SafeFreeCredentials _Target; - - private SafeCredentialReference(SafeFreeCredentials target) - : base() - { - // Bumps up the refcount on Target to signify that target handle is statically cached so - // its dispose should be postponed - bool b = false; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - target.DangerousAddRef(ref b); - } - catch - { - if (b) - { - target.DangerousRelease(); - b = false; - } - } - finally - { - if (b) - { - _Target = target; - SetHandle(new IntPtr(0)); // make this handle valid - } - } - } - - internal static SafeCredentialReference CreateReference(SafeFreeCredentials target) - { - SafeCredentialReference result = new SafeCredentialReference(target); - if (result.IsInvalid) - { - return null; - } - - return result; - } - - protected override bool ReleaseHandle() - { - SafeFreeCredentials target = _Target; - if (target != null) - { - target.DangerousRelease(); - } - _Target = null; - return true; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs deleted file mode 100644 index 27aaeb05db..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeDeleteContext.cs +++ /dev/null @@ -1,724 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - internal sealed class SafeDeleteContext : SafeHandle - { - private const string DummyStr = " "; - private static readonly byte[] DummyBytes = new byte[] { 0 }; - - // ATN: _handle is internal since it is used on PInvokes by other wrapper methods. - // However all such wrappers MUST manually and reliably adjust refCounter of SafeDeleteContext handle. - - internal SSPIHandle _handle; - - private SafeFreeCredentials _effectiveCredential; - - private SafeDeleteContext() - : base(IntPtr.Zero, true) - { - _handle = new SSPIHandle(); - } - - public override bool IsInvalid - { - get - { - return IsClosed || _handle.IsZero; - } - } - - public override string ToString() - { - return _handle.ToString(); - } - - //------------------------------------------------------------------- - internal static unsafe int InitializeSecurityContext(ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, - string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, - SecurityBuffer outSecBuffer, ref ContextFlags outFlags) - { - GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::InitializeSecurityContext()|outSecBuffer != null"); - GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::InitializeSecurityContext()|inSecBuffer == null || inSecBuffers == null"); - - if (inCredentials == null) - { - throw new ArgumentNullException("inCredentials"); - } - - SecurityBufferDescriptor inSecurityBufferDescriptor = null; - if (inSecBuffer != null) - { - inSecurityBufferDescriptor = new SecurityBufferDescriptor(1); - } - else if (inSecBuffers != null) - { - inSecurityBufferDescriptor = new SecurityBufferDescriptor(inSecBuffers.Length); - } - SecurityBufferDescriptor outSecurityBufferDescriptor = new SecurityBufferDescriptor(1); - - // actually this is returned in outFlags - bool isSspiAllocated = (inFlags & ContextFlags.AllocateMemory) != 0 ? true : false; - - int errorCode = -1; - - SSPIHandle contextHandle = new SSPIHandle(); - if (refContext != null) - { - contextHandle = refContext._handle; - } - - // these are pinned user byte arrays passed along with SecurityBuffers - GCHandle[] pinnedInBytes = null; - GCHandle pinnedOutBytes = new GCHandle(); - // optional output buffer that may need to be freed - SafeFreeContextBuffer outFreeContextBuffer = null; - try - { - pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); - SecurityBufferStruct[] inUnmanagedBuffer = new SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; - fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) - { - if (inSecurityBufferDescriptor != null) - { - // Fix Descriptor pointer that points to unmanaged SecurityBuffers - inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; - pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; - SecurityBuffer securityBuffer; - for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) - { - securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; - if (securityBuffer != null) - { - // Copy the SecurityBuffer content into unmanaged place holder - inUnmanagedBuffer[index].count = securityBuffer.size; - inUnmanagedBuffer[index].type = securityBuffer.type; - - // use the unmanaged token if it's not null; otherwise use the managed buffer - if (securityBuffer.unmanagedToken != null) - { - inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); - } - else if (securityBuffer.token == null || securityBuffer.token.Length == 0) - { - inUnmanagedBuffer[index].token = IntPtr.Zero; - } - else - { - pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); - inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); - } - } - } - } - - SecurityBufferStruct[] outUnmanagedBuffer = new SecurityBufferStruct[1]; - fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) - { - // Fix Descriptor pointer that points to unmanaged SecurityBuffers - outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; - outUnmanagedBuffer[0].count = outSecBuffer.size; - outUnmanagedBuffer[0].type = outSecBuffer.type; - if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) - { - outUnmanagedBuffer[0].token = IntPtr.Zero; - } - else - { - outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); - } - if (isSspiAllocated) - { - outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); - } - - if (refContext == null || refContext.IsInvalid) - { - refContext = new SafeDeleteContext(); - } - - if (targetName == null || targetName.Length == 0) - { - targetName = DummyStr; - } - - fixed (char* namePtr = targetName) - { - errorCode = MustRunInitializeSecurityContext( - ref inCredentials, - contextHandle.IsZero ? null : &contextHandle, - (byte*)(((object)targetName == (object)DummyStr) ? null : namePtr), - inFlags, - endianness, - inSecurityBufferDescriptor, - refContext, - outSecurityBufferDescriptor, - ref outFlags, - outFreeContextBuffer); - } - - GlobalLog.Print("SafeDeleteContext:InitializeSecurityContext Marshalling OUT buffer"); - // Get unmanaged buffer with index 0 as the only one passed into PInvoke - outSecBuffer.size = outUnmanagedBuffer[0].count; - outSecBuffer.type = outUnmanagedBuffer[0].type; - if (outSecBuffer.size > 0) - { - outSecBuffer.token = new byte[outSecBuffer.size]; - Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); - } - else - { - outSecBuffer.token = null; - } - } - } - } - finally - { - if (pinnedInBytes != null) - { - for (int index = 0; index < pinnedInBytes.Length; index++) - { - if (pinnedInBytes[index].IsAllocated) - { - pinnedInBytes[index].Free(); - } - } - } - if (pinnedOutBytes.IsAllocated) - { - pinnedOutBytes.Free(); - } - - if (outFreeContextBuffer != null) - { - outFreeContextBuffer.Dispose(); - } - } - - GlobalLog.Leave("SafeDeleteContext::InitializeSecurityContext() unmanaged InitializeSecurityContext()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + ValidationHelper.ToString(refContext)); - - return errorCode; - } - - // After PINvoke call the method will fix the handleTemplate.handle with the returned value. - // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. - // - // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system. - - private static unsafe int MustRunInitializeSecurityContext( - ref SafeFreeCredentials inCredentials, - void* inContextPtr, - byte* targetName, - ContextFlags inFlags, - Endianness endianness, - SecurityBufferDescriptor inputBuffer, - SafeDeleteContext outContext, - SecurityBufferDescriptor outputBuffer, - ref ContextFlags attributes, - SafeFreeContextBuffer handleTemplate) - { - int errorCode = (int)SecurityStatus.InvalidHandle; - bool b1 = false; - bool b2 = false; - - // Run the body of this method as a non-interruptible block. - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - inCredentials.DangerousAddRef(ref b1); - outContext.DangerousAddRef(ref b2); - } - catch (Exception e) - { - if (b1) - { - inCredentials.DangerousRelease(); - b1 = false; - } - if (b2) - { - outContext.DangerousRelease(); - b2 = false; - } - - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - SSPIHandle credentialHandle = inCredentials._handle; - long timeStamp; - - if (!b1) - { - // caller should retry - inCredentials = null; - } - else if (b1 && b2) - { - errorCode = UnsafeNclNativeMethods.SafeNetHandles.InitializeSecurityContextW( - ref credentialHandle, - inContextPtr, - targetName, - inFlags, - 0, - endianness, - inputBuffer, - 0, - ref outContext._handle, - outputBuffer, - ref attributes, - out timeStamp); - - // When a credential handle is first associated with the context we keep credential - // ref count bumped up to ensure ordered finalization. - // If the credential handle has been changed we de-ref the old one and associate the - // context with the new cred handle but only if the call was successful. - if (outContext._effectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) - { - // Disassociate the previous credential handle - if (outContext._effectiveCredential != null) - { - outContext._effectiveCredential.DangerousRelease(); - } - outContext._effectiveCredential = inCredentials; - } - else - { - inCredentials.DangerousRelease(); - } - - outContext.DangerousRelease(); - - // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. - if (handleTemplate != null) - { - handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); // ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes - if (handleTemplate.IsInvalid) - { - handleTemplate.SetHandleAsInvalid(); - } - } - } - - if (inContextPtr == null && (errorCode & 0x80000000) != 0) - { - // an error on the first call, need to set the out handle to invalid value - outContext._handle.SetToInvalid(); - } - } - - return errorCode; - } - - //------------------------------------------------------------------- - internal static unsafe int AcceptSecurityContext(ref SafeFreeCredentials inCredentials, ref SafeDeleteContext refContext, - ContextFlags inFlags, Endianness endianness, SecurityBuffer inSecBuffer, SecurityBuffer[] inSecBuffers, SecurityBuffer outSecBuffer, - ref ContextFlags outFlags) - { - GlobalLog.Assert(outSecBuffer != null, "SafeDeleteContext::AcceptSecurityContext()|outSecBuffer != null"); - GlobalLog.Assert(inSecBuffer == null || inSecBuffers == null, "SafeDeleteContext::AcceptSecurityContext()|inSecBuffer == null || inSecBuffers == null"); - - if (inCredentials == null) - { - throw new ArgumentNullException("inCredentials"); - } - - SecurityBufferDescriptor inSecurityBufferDescriptor = null; - if (inSecBuffer != null) - { - inSecurityBufferDescriptor = new SecurityBufferDescriptor(1); - } - else if (inSecBuffers != null) - { - inSecurityBufferDescriptor = new SecurityBufferDescriptor(inSecBuffers.Length); - } - SecurityBufferDescriptor outSecurityBufferDescriptor = new SecurityBufferDescriptor(1); - - // actually this is returned in outFlags - bool isSspiAllocated = (inFlags & ContextFlags.AllocateMemory) != 0 ? true : false; - - int errorCode = -1; - - SSPIHandle contextHandle = new SSPIHandle(); - if (refContext != null) - { - contextHandle = refContext._handle; - } - - // these are pinned user byte arrays passed along with SecurityBuffers - GCHandle[] pinnedInBytes = null; - GCHandle pinnedOutBytes = new GCHandle(); - // optional output buffer that may need to be freed - SafeFreeContextBuffer outFreeContextBuffer = null; - try - { - pinnedOutBytes = GCHandle.Alloc(outSecBuffer.token, GCHandleType.Pinned); - SecurityBufferStruct[] inUnmanagedBuffer = new SecurityBufferStruct[inSecurityBufferDescriptor == null ? 1 : inSecurityBufferDescriptor.Count]; - fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) - { - if (inSecurityBufferDescriptor != null) - { - // Fix Descriptor pointer that points to unmanaged SecurityBuffers - inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; - pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; - SecurityBuffer securityBuffer; - for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) - { - securityBuffer = inSecBuffer != null ? inSecBuffer : inSecBuffers[index]; - if (securityBuffer != null) - { - // Copy the SecurityBuffer content into unmanaged place holder - inUnmanagedBuffer[index].count = securityBuffer.size; - inUnmanagedBuffer[index].type = securityBuffer.type; - - // use the unmanaged token if it's not null; otherwise use the managed buffer - if (securityBuffer.unmanagedToken != null) - { - inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); - } - else if (securityBuffer.token == null || securityBuffer.token.Length == 0) - { - inUnmanagedBuffer[index].token = IntPtr.Zero; - } - else - { - pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); - inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); - } - } - } - } - SecurityBufferStruct[] outUnmanagedBuffer = new SecurityBufferStruct[1]; - fixed (void* outUnmanagedBufferPtr = outUnmanagedBuffer) - { - // Fix Descriptor pointer that points to unmanaged SecurityBuffers - outSecurityBufferDescriptor.UnmanagedPointer = outUnmanagedBufferPtr; - // Copy the SecurityBuffer content into unmanaged place holder - outUnmanagedBuffer[0].count = outSecBuffer.size; - outUnmanagedBuffer[0].type = outSecBuffer.type; - - if (outSecBuffer.token == null || outSecBuffer.token.Length == 0) - { - outUnmanagedBuffer[0].token = IntPtr.Zero; - } - else - { - outUnmanagedBuffer[0].token = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset); - } - if (isSspiAllocated) - { - outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle(); - } - - if (refContext == null || refContext.IsInvalid) - { - refContext = new SafeDeleteContext(); - } - - errorCode = MustRunAcceptSecurityContext( - ref inCredentials, - contextHandle.IsZero ? null : &contextHandle, - inSecurityBufferDescriptor, - inFlags, - endianness, - refContext, - outSecurityBufferDescriptor, - ref outFlags, - outFreeContextBuffer); - - GlobalLog.Print("SafeDeleteContext:AcceptSecurityContext Marshalling OUT buffer"); - // Get unmanaged buffer with index 0 as the only one passed into PInvoke - outSecBuffer.size = outUnmanagedBuffer[0].count; - outSecBuffer.type = outUnmanagedBuffer[0].type; - if (outSecBuffer.size > 0) - { - outSecBuffer.token = new byte[outSecBuffer.size]; - Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size); - } - else - { - outSecBuffer.token = null; - } - } - } - } - finally - { - if (pinnedInBytes != null) - { - for (int index = 0; index < pinnedInBytes.Length; index++) - { - if (pinnedInBytes[index].IsAllocated) - { - pinnedInBytes[index].Free(); - } - } - } - - if (pinnedOutBytes.IsAllocated) - { - pinnedOutBytes.Free(); - } - - if (outFreeContextBuffer != null) - { - outFreeContextBuffer.Dispose(); - } - } - - GlobalLog.Leave("SafeDeleteContext::AcceptSecurityContex() unmanaged AcceptSecurityContex()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + ValidationHelper.ToString(refContext)); - - return errorCode; - } - - // After PINvoke call the method will fix the handleTemplate.handle with the returned value. - // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. - // - // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system. - - private static unsafe int MustRunAcceptSecurityContext( - ref SafeFreeCredentials inCredentials, - void* inContextPtr, - SecurityBufferDescriptor inputBuffer, - ContextFlags inFlags, - Endianness endianness, - SafeDeleteContext outContext, - SecurityBufferDescriptor outputBuffer, - ref ContextFlags outFlags, - SafeFreeContextBuffer handleTemplate) - { - int errorCode = (int)SecurityStatus.InvalidHandle; - bool b1 = false; - bool b2 = false; - - // Run the body of this method as a non-interruptible block. - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - inCredentials.DangerousAddRef(ref b1); - outContext.DangerousAddRef(ref b2); - } - catch (Exception e) - { - if (b1) - { - inCredentials.DangerousRelease(); - b1 = false; - } - if (b2) - { - outContext.DangerousRelease(); - b2 = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - SSPIHandle credentialHandle = inCredentials._handle; - long timeStamp; - - if (!b1) - { - // caller should retry - inCredentials = null; - } - else if (b1 && b2) - { - errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcceptSecurityContext( - ref credentialHandle, - inContextPtr, - inputBuffer, - inFlags, - endianness, - ref outContext._handle, - outputBuffer, - ref outFlags, - out timeStamp); - - // When a credential handle is first associated with the context we keep credential - // ref count bumped up to ensure ordered finalization. - // If the credential handle has been changed we de-ref the old one and associate the - // context with the new cred handle but only if the call was successful. - if (outContext._effectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) - { - // Disassociate the previous credential handle - if (outContext._effectiveCredential != null) - { - outContext._effectiveCredential.DangerousRelease(); - } - outContext._effectiveCredential = inCredentials; - } - else - { - inCredentials.DangerousRelease(); - } - - outContext.DangerousRelease(); - - // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. - if (handleTemplate != null) - { - handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); // ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes - if (handleTemplate.IsInvalid) - { - handleTemplate.SetHandleAsInvalid(); - } - } - } - - if (inContextPtr == null && (errorCode & 0x80000000) != 0) - { - // an error on the first call, need to set the out handle to invalid value - outContext._handle.SetToInvalid(); - } - } - - return errorCode; - } - - internal static unsafe int CompleteAuthToken(ref SafeDeleteContext refContext, SecurityBuffer[] inSecBuffers) - { - GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken"); - GlobalLog.Print(" refContext = " + ValidationHelper.ToString(refContext)); - GlobalLog.Assert(inSecBuffers != null, "SafeDeleteContext::CompleteAuthToken()|inSecBuffers == null"); - SecurityBufferDescriptor inSecurityBufferDescriptor = new SecurityBufferDescriptor(inSecBuffers.Length); - - int errorCode = (int)SecurityStatus.InvalidHandle; - - // these are pinned user byte arrays passed along with SecurityBuffers - GCHandle[] pinnedInBytes = null; - - SecurityBufferStruct[] inUnmanagedBuffer = new SecurityBufferStruct[inSecurityBufferDescriptor.Count]; - fixed (void* inUnmanagedBufferPtr = inUnmanagedBuffer) - { - // Fix Descriptor pointer that points to unmanaged SecurityBuffers - inSecurityBufferDescriptor.UnmanagedPointer = inUnmanagedBufferPtr; - pinnedInBytes = new GCHandle[inSecurityBufferDescriptor.Count]; - SecurityBuffer securityBuffer; - for (int index = 0; index < inSecurityBufferDescriptor.Count; ++index) - { - securityBuffer = inSecBuffers[index]; - if (securityBuffer != null) - { - inUnmanagedBuffer[index].count = securityBuffer.size; - inUnmanagedBuffer[index].type = securityBuffer.type; - - // use the unmanaged token if it's not null; otherwise use the managed buffer - if (securityBuffer.unmanagedToken != null) - { - inUnmanagedBuffer[index].token = securityBuffer.unmanagedToken.DangerousGetHandle(); - } - else if (securityBuffer.token == null || securityBuffer.token.Length == 0) - { - inUnmanagedBuffer[index].token = IntPtr.Zero; - } - else - { - pinnedInBytes[index] = GCHandle.Alloc(securityBuffer.token, GCHandleType.Pinned); - inUnmanagedBuffer[index].token = Marshal.UnsafeAddrOfPinnedArrayElement(securityBuffer.token, securityBuffer.offset); - } - } - } - - SSPIHandle contextHandle = new SSPIHandle(); - if (refContext != null) - { - contextHandle = refContext._handle; - } - try - { - if (refContext == null || refContext.IsInvalid) - { - refContext = new SafeDeleteContext(); - } - - bool b = false; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - refContext.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - refContext.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - errorCode = UnsafeNclNativeMethods.SafeNetHandles.CompleteAuthToken(contextHandle.IsZero ? null : &contextHandle, inSecurityBufferDescriptor); - refContext.DangerousRelease(); - } - } - } - finally - { - if (pinnedInBytes != null) - { - for (int index = 0; index < pinnedInBytes.Length; index++) - { - if (pinnedInBytes[index].IsAllocated) - { - pinnedInBytes[index].Free(); - } - } - } - } - } - - GlobalLog.Leave("SafeDeleteContext::CompleteAuthToken() unmanaged CompleteAuthToken()", "errorCode:0x" + errorCode.ToString("x8") + " refContext:" + ValidationHelper.ToString(refContext)); - - return errorCode; - } - - protected override bool ReleaseHandle() - { - if (this._effectiveCredential != null) - { - this._effectiveCredential.DangerousRelease(); - } - - return UnsafeNclNativeMethods.SafeNetHandles.DeleteSecurityContext(ref _handle) == 0; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs deleted file mode 100644 index ddb35763b4..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCertContext.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.ConstrainedExecution; -using System.Security; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.AspNet.Security.Windows -{ - [SuppressUnmanagedCodeSecurity] - internal sealed class SafeFreeCertContext : SafeHandleZeroOrMinusOneIsInvalid - { - internal SafeFreeCertContext() - : base(true) - { - } - - // This must be ONLY called from this file within a CER. - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal unsafe void Set(IntPtr value) - { - this.handle = value; - } - - protected override bool ReleaseHandle() - { - UnsafeNclNativeMethods.SafeNetHandles.CertFreeCertificateContext(handle); - return true; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs deleted file mode 100644 index 398d01bffc..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBuffer.cs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; -using System.Runtime.InteropServices; -using System.Security; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.AspNet.Security.Windows -{ - [SuppressUnmanagedCodeSecurity] - internal sealed class SafeFreeContextBuffer : SafeHandleZeroOrMinusOneIsInvalid - { - private SafeFreeContextBuffer() - : base(true) - { - } - - // This must be ONLY called from this file and in the context of a CER - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal unsafe void Set(IntPtr value) - { - this.handle = value; - } - - internal static int EnumeratePackages(out int pkgnum, out SafeFreeContextBuffer pkgArray) - { - int res = -1; - res = UnsafeNclNativeMethods.SafeNetHandles.EnumerateSecurityPackagesW(out pkgnum, out pkgArray); - if (res != 0 && pkgArray != null) - { - pkgArray.SetHandleAsInvalid(); - } - return res; - } - - internal static SafeFreeContextBuffer CreateEmptyHandle() - { - return new SafeFreeContextBuffer(); - } - - // After PINvoke call the method will fix the refHandle.handle with the returned value. - // The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned. - // - // This method switches between three non-interruptible helper methods. (This method can't be both non-interruptible and - // reference imports from all three DLLs - doing so would cause all three DLLs to try to be bound to.) - - public static unsafe int QueryContextAttributes(SafeDeleteContext phContext, ContextAttribute contextAttribute, byte* buffer, SafeHandle refHandle) - { - int status = (int)SecurityStatus.InvalidHandle; - bool b = false; - - // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit - // one of the following methods. So run within a CER non-interruptible block. - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - phContext.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - phContext.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - status = UnsafeNclNativeMethods.SafeNetHandles.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); - phContext.DangerousRelease(); - } - - if (status == 0 && refHandle != null) - { - if (refHandle is SafeFreeContextBuffer) - { - ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); - } - else - { - ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); - } - } - - if (status != 0 && refHandle != null) - { - refHandle.SetHandleAsInvalid(); - } - } - - return status; - } - - public static int SetContextAttributes(SafeDeleteContext phContext, ContextAttribute contextAttribute, byte[] buffer) - { - int status = (int)SecurityStatus.InvalidHandle; - bool b = false; - - // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing - // to jit one of the following methods. So run within a CER non-interruptible block. - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - phContext.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - phContext.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - status = UnsafeNclNativeMethods.SafeNetHandles.SetContextAttributesW( - ref phContext._handle, contextAttribute, buffer, buffer.Length); - phContext.DangerousRelease(); - } - } - - return status; - } - - protected override bool ReleaseHandle() - { - return UnsafeNclNativeMethods.SafeNetHandles.FreeContextBuffer(handle) == 0; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs deleted file mode 100644 index 72972dab9e..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeContextBufferChannelBinding.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; -using System.Security; -using System.Security.Authentication.ExtendedProtection; - -namespace Microsoft.AspNet.Security.Windows -{ - [SuppressUnmanagedCodeSecurity] - internal sealed class SafeFreeContextBufferChannelBinding : ChannelBinding - { - private int size; - - public override int Size - { - get { return size; } - } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal unsafe void Set(IntPtr value) - { - this.handle = value; - } - - internal static SafeFreeContextBufferChannelBinding CreateEmptyHandle() - { - return new SafeFreeContextBufferChannelBinding(); - } - - public static unsafe int QueryContextChannelBinding(SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, - SafeFreeContextBufferChannelBinding refHandle) - { - int status = (int)SecurityStatus.InvalidHandle; - bool b = false; - - // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit - // one of the following methods. So run within a CER non-interruptible block. - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - phContext.DangerousAddRef(ref b); - } - catch (Exception e) - { - if (b) - { - phContext.DangerousRelease(); - b = false; - } - if (!(e is ObjectDisposedException)) - { - throw; - } - } - finally - { - if (b) - { - status = UnsafeNclNativeMethods.SafeNetHandles.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer); - phContext.DangerousRelease(); - } - - if (status == 0 && refHandle != null) - { - refHandle.Set((*buffer).pBindings); - refHandle.size = (*buffer).BindingsLength; - } - - if (status != 0 && refHandle != null) - { - refHandle.SetHandleAsInvalid(); - } - } - - return status; - } - - protected override bool ReleaseHandle() - { - return UnsafeNclNativeMethods.SafeNetHandles.FreeContextBuffer(handle) == 0; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs deleted file mode 100644 index b07be9aff0..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeFreeCredentials.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - internal sealed class SafeFreeCredentials : SafeHandle - { - internal SSPIHandle _handle; // should be always used as by ref in PINvokes parameters - - private SafeFreeCredentials() - : base(IntPtr.Zero, true) - { - _handle = new SSPIHandle(); - } - - public override bool IsInvalid - { - get { return IsClosed || _handle.IsZero; } - } - - protected override bool ReleaseHandle() - { - return UnsafeNclNativeMethods.SafeNetHandles.FreeCredentialsHandle(ref _handle) == 0; - } - - public static unsafe int AcquireCredentialsHandle(string package, CredentialUse intent, ref AuthIdentity authdata, - out SafeFreeCredentials outCredential) - { - GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#1(" - + package + ", " - + intent + ", " - + authdata + ")"); - - int errorCode = -1; - long timeStamp; - - outCredential = new SafeFreeCredentials(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - } - finally - { - errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcquireCredentialsHandleW( - null, - package, - (int)intent, - null, - ref authdata, - null, - null, - ref outCredential._handle, - out timeStamp); - } - - if (errorCode != 0) - { - outCredential.SetHandleAsInvalid(); - } - return errorCode; - } - - public static unsafe int AcquireDefaultCredential(string package, CredentialUse intent, out SafeFreeCredentials outCredential) - { - GlobalLog.Print("SafeFreeCredentials::AcquireDefaultCredential(" - + package + ", " - + intent + ")"); - - int errorCode = -1; - long timeStamp; - - outCredential = new SafeFreeCredentials(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - } - finally - { - errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcquireCredentialsHandleW( - null, - package, - (int)intent, - null, - IntPtr.Zero, - null, - null, - ref outCredential._handle, - out timeStamp); - } - - if (errorCode != 0) - { - outCredential.SetHandleAsInvalid(); - } - return errorCode; - } - - // This overload is only called on Win7+ where SspiEncodeStringsAsAuthIdentity() was used to - // create the authData blob. - public static unsafe int AcquireCredentialsHandle( - string package, - CredentialUse intent, - ref SafeSspiAuthDataHandle authdata, - out SafeFreeCredentials outCredential) - { - int errorCode = -1; - long timeStamp; - - outCredential = new SafeFreeCredentials(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - } - finally - { - errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcquireCredentialsHandleW( - null, - package, - (int)intent, - null, - authdata, - null, - null, - ref outCredential._handle, - out timeStamp); - } - - if (errorCode != 0) - { - outCredential.SetHandleAsInvalid(); - } - return errorCode; - } - - public static unsafe int AcquireCredentialsHandle(string package, CredentialUse intent, ref SecureCredential authdata, - out SafeFreeCredentials outCredential) - { - GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#2(" - + package + ", " - + intent + ", " - + authdata + ")"); - - int errorCode = -1; - long timeStamp; - - // If there is a certificate, wrap it into an array. - // Not threadsafe. - IntPtr copiedPtr = authdata.certContextArray; - try - { - IntPtr certArrayPtr = new IntPtr(&copiedPtr); - if (copiedPtr != IntPtr.Zero) - { - authdata.certContextArray = certArrayPtr; - } - - outCredential = new SafeFreeCredentials(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - } - finally - { - errorCode = UnsafeNclNativeMethods.SafeNetHandles.AcquireCredentialsHandleW( - null, - package, - (int)intent, - null, - ref authdata, - null, - null, - ref outCredential._handle, - out timeStamp); - } - } - finally - { - authdata.certContextArray = copiedPtr; - } - - if (errorCode != 0) - { - outCredential.SetHandleAsInvalid(); - } - return errorCode; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs deleted file mode 100644 index ac65383822..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeLocalFree.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Security; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.AspNet.Security.Windows -{ - [SuppressUnmanagedCodeSecurity] - internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid - { - private const int LmemFixed = 0; - private const int NULL = 0; - - // This returned handle cannot be modified by the application. - public static SafeLocalFree Zero = new SafeLocalFree(false); - - private SafeLocalFree() - : base(true) - { - } - - private SafeLocalFree(bool ownsHandle) - : base(ownsHandle) - { - } - - public static SafeLocalFree LocalAlloc(int cb) - { - SafeLocalFree result = UnsafeNclNativeMethods.SafeNetHandles.LocalAlloc(LmemFixed, (UIntPtr)cb); - if (result.IsInvalid) - { - result.SetHandleAsInvalid(); - throw new OutOfMemoryException(); - } - return result; - } - - protected override bool ReleaseHandle() - { - return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs deleted file mode 100644 index d687003b2f..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SafeSspiAuthDataHandle.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace Microsoft.AspNet.Security.Windows -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.ConstrainedExecution; - using System.Runtime.InteropServices; - using System.Security; - using System.Security.Authentication.ExtendedProtection; - using System.Threading; - using Microsoft.Win32.SafeHandles; - - [SuppressUnmanagedCodeSecurity] - internal sealed class SafeSspiAuthDataHandle : SafeHandleZeroOrMinusOneIsInvalid - { - public SafeSspiAuthDataHandle() - : base(true) - { - } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - protected override bool ReleaseHandle() - { - return UnsafeNclNativeMethods.SspiHelper.SspiFreeAuthIdentity(handle) == SecurityStatus.OK; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs deleted file mode 100644 index 780678a8f5..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SchProtocols.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; - -namespace Microsoft.AspNet.Security.Windows -{ - // From Schannel.h - [Flags] - internal enum SchProtocols - { - Zero = 0, - PctClient = 0x00000002, - PctServer = 0x00000001, - Pct = (PctClient | PctServer), - Ssl2Client = 0x00000008, - Ssl2Server = 0x00000004, - Ssl2 = (Ssl2Client | Ssl2Server), - Ssl3Client = 0x00000020, - Ssl3Server = 0x00000010, - Ssl3 = (Ssl3Client | Ssl3Server), - Tls10Client = 0x00000080, - Tls10Server = 0x00000040, - Tls10 = (Tls10Client | Tls10Server), - Tls11Client = 0x00000200, - Tls11Server = 0x00000100, - Tls11 = (Tls11Client | Tls11Server), - Tls12Client = 0x00000800, - Tls12Server = 0x00000400, - Tls12 = (Tls12Client | Tls12Server), - Ssl3Tls = (Ssl3 | Tls10), - UniClient = unchecked((int)0x80000000), - UniServer = 0x40000000, - Unified = (UniClient | UniServer), - ClientMask = (PctClient | Ssl2Client | Ssl3Client | Tls10Client | Tls11Client | Tls12Client | UniClient), - ServerMask = (PctServer | Ssl2Server | Ssl3Server | Tls10Server | Tls11Server | Tls12Server | UniServer) - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs deleted file mode 100644 index 1978c950b6..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecSizes.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace Microsoft.AspNet.Security.Windows -{ - using System; - using System.ComponentModel; - using System.Diagnostics; - using System.Globalization; - using System.Runtime.InteropServices; - - [StructLayout(LayoutKind.Sequential)] - internal class SecSizes - { - public readonly int MaxToken; - public readonly int MaxSignature; - public readonly int BlockSize; - public readonly int SecurityTrailer; - - internal unsafe SecSizes(byte[] memory) - { - fixed (void* voidPtr = memory) - { - IntPtr unmanagedAddress = new IntPtr(voidPtr); - try - { - MaxToken = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress)); - MaxSignature = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 4)); - BlockSize = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 8)); - SecurityTrailer = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 12)); - } - catch (OverflowException) - { - GlobalLog.Assert(false, "SecSizes::.ctor", "Negative size."); - throw; - } - } - } - public static readonly int SizeOf = Marshal.SizeOf(typeof(SecSizes)); - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs deleted file mode 100644 index d5fe3605ae..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBuffer.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Security.Authentication.ExtendedProtection; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class SecurityBuffer - { - public int size; - public BufferType type; - public byte[] token; - public SafeHandle unmanagedToken; - public int offset; - - public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) - { - GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range. [" + offset + "]"); - GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range. [" + size + "]"); - - this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length); - this.size = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset); - this.type = tokentype; - this.token = size == 0 ? null : data; - } - - public SecurityBuffer(byte[] data, BufferType tokentype) - { - this.size = data == null ? 0 : data.Length; - this.type = tokentype; - this.token = size == 0 ? null : data; - } - - public SecurityBuffer(int size, BufferType tokentype) - { - GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range. [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]"); - - this.size = size; - this.type = tokentype; - this.token = size == 0 ? null : new byte[size]; - } - - public SecurityBuffer(ChannelBinding binding) - { - this.size = (binding == null ? 0 : binding.Size); - this.type = BufferType.ChannelBindings; - this.unmanagedToken = binding; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs deleted file mode 100644 index ee2d5fc218..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityBufferDescriptor.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - [StructLayout(LayoutKind.Sequential)] - internal unsafe class SecurityBufferDescriptor - { - /* - typedef struct _SecBufferDesc { - ULONG ulVersion; - ULONG cBuffers; - PSecBuffer pBuffers; - } SecBufferDesc, * PSecBufferDesc; - */ - public readonly int Version; - public readonly int Count; - public void* UnmanagedPointer; - - public SecurityBufferDescriptor(int count) - { - Version = 0; - Count = count; - UnmanagedPointer = null; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs deleted file mode 100644 index c25ba8da8d..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SecurityPackageInfoClass.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Globalization; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class SecurityPackageInfoClass - { - private int _capabilities = 0; - private short _version = 0; - private short _rpcid = 0; - private int _maxToken = 0; - private string _name = null; - private string _comment = null; - - /* - * This is to support SSL under semi trusted environment. - * Note that it is only for SSL with no client cert - */ - internal SecurityPackageInfoClass(SafeHandle safeHandle, int index) - { - if (safeHandle.IsInvalid) - { - GlobalLog.Print("SecurityPackageInfoClass::.ctor() the pointer is invalid: " + (safeHandle.DangerousGetHandle()).ToString("x")); - return; - } - IntPtr unmanagedAddress = IntPtrHelper.Add(safeHandle.DangerousGetHandle(), SecurityPackageInfo.Size * index); - GlobalLog.Print("SecurityPackageInfoClass::.ctor() unmanagedPointer: " + ((long)unmanagedAddress).ToString("x")); - - _capabilities = Marshal.ReadInt32(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Capabilities")); - _version = Marshal.ReadInt16(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Version")); - _rpcid = Marshal.ReadInt16(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "RPCID")); - _maxToken = Marshal.ReadInt32(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "MaxToken")); - - IntPtr unmanagedString; - - unmanagedString = Marshal.ReadIntPtr(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Name")); - if (unmanagedString != IntPtr.Zero) - { - _name = Marshal.PtrToStringUni(unmanagedString); - GlobalLog.Print("Name: " + Name); - } - - unmanagedString = Marshal.ReadIntPtr(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Comment")); - if (unmanagedString != IntPtr.Zero) - { - _comment = Marshal.PtrToStringUni(unmanagedString); - GlobalLog.Print("Comment: " + _comment); - } - - GlobalLog.Print("SecurityPackageInfoClass::.ctor(): " + ToString()); - } - - internal int MaxToken - { - get { return _maxToken; } - } - - internal string Name - { - get { return _name; } - } - - public override string ToString() - { - return "Capabilities:" + String.Format(CultureInfo.InvariantCulture, "0x{0:x}", _capabilities) - + " Version:" + _version.ToString(NumberFormatInfo.InvariantInfo) - + " RPCID:" + _rpcid.ToString(NumberFormatInfo.InvariantInfo) - + " MaxToken:" + MaxToken.ToString(NumberFormatInfo.InvariantInfo) - + " Name:" + ((Name == null) ? "(null)" : Name) - + " Comment:" + ((_comment == null) ? "(null)" : _comment); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs deleted file mode 100644 index e96f28dea2..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/SslConnectionInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - [StructLayout(LayoutKind.Sequential)] - internal class SslConnectionInfo - { - public readonly int Protocol; - public readonly int DataCipherAlg; - public readonly int DataKeySize; - public readonly int DataHashAlg; - public readonly int DataHashKeySize; - public readonly int KeyExchangeAlg; - public readonly int KeyExchKeySize; - - internal unsafe SslConnectionInfo(byte[] nativeBuffer) - { - fixed (void* voidPtr = nativeBuffer) - { - IntPtr unmanagedAddress = new IntPtr(voidPtr); - Protocol = Marshal.ReadInt32(unmanagedAddress); - DataCipherAlg = Marshal.ReadInt32(unmanagedAddress, 4); - DataKeySize = Marshal.ReadInt32(unmanagedAddress, 8); - DataHashAlg = Marshal.ReadInt32(unmanagedAddress, 12); - DataHashKeySize = Marshal.ReadInt32(unmanagedAddress, 16); - KeyExchangeAlg = Marshal.ReadInt32(unmanagedAddress, 20); - KeyExchKeySize = Marshal.ReadInt32(unmanagedAddress, 24); - } - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs deleted file mode 100644 index 3c17afa5af..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/StreamSizes.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNet.Security.Windows -{ - [StructLayout(LayoutKind.Sequential)] - internal class StreamSizes - { - public int header; - public int trailer; - public int maximumMessage; - public int buffersCount; - public int blockSize; - - internal unsafe StreamSizes(byte[] memory) - { - fixed (void* voidPtr = memory) - { - IntPtr unmanagedAddress = new IntPtr(voidPtr); - try - { - header = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress)); - trailer = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 4)); - maximumMessage = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 8)); - buffersCount = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 12)); - blockSize = (int)checked((uint)Marshal.ReadInt32(unmanagedAddress, 16)); - } - catch (OverflowException) - { - GlobalLog.Assert(false, "StreamSizes::.ctor", "Negative size."); - throw; - } - } - } - public static readonly int SizeOf = Marshal.SizeOf(typeof(StreamSizes)); - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs deleted file mode 100644 index 7084e0e206..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NativeInterop/UnsafeNativeMethods.cs +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.ConstrainedExecution; -using System.Runtime.InteropServices; -using System.Security; - -namespace Microsoft.AspNet.Security.Windows -{ - [System.Security.SuppressUnmanagedCodeSecurityAttribute] - internal static class UnsafeNclNativeMethods - { -#if ASPNETCORE50 - private const string sspicli_LIB = "sspicli.dll"; - private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; - private const string api_ms_win_core_handle_LIB = "api-ms-win-core-handle-l1-1-0.dll"; - private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-1.dll"; - private const string api_ms_win_core_heap_obsolete_LIB = "api-ms-win-core-heap-obsolete-l1-1-0.dll"; -#else - private const string KERNEL32 = "kernel32.dll"; -#endif - private const string SECUR32 = "secur32.dll"; - private const string CRYPT32 = "crypt32.dll"; - -#if ASPNETCORE50 - [DllImport(api_ms_win_core_processthreads_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] -#endif - internal static extern uint GetCurrentThreadId(); - - - [System.Security.SuppressUnmanagedCodeSecurityAttribute] - internal static class SafeNetHandles - { - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern int FreeContextBuffer( - [In] IntPtr contextBuffer); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern int FreeCredentialsHandle( - ref SSPIHandle handlePtr); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern int DeleteSecurityContext( - ref SSPIHandle handlePtr); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - internal static unsafe extern int AcceptSecurityContext( - ref SSPIHandle credentialHandle, - [In] void* inContextPtr, - [In] SecurityBufferDescriptor inputBuffer, - [In] ContextFlags inFlags, - [In] Endianness endianness, - ref SSPIHandle outContextPtr, - [In, Out] SecurityBufferDescriptor outputBuffer, - [In, Out] ref ContextFlags attributes, - out long timeStamp); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - internal static unsafe extern int QueryContextAttributesW( - ref SSPIHandle contextHandle, - [In] ContextAttribute attribute, - [In] void* buffer); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - internal static unsafe extern int SetContextAttributesW( - ref SSPIHandle contextHandle, - [In] ContextAttribute attribute, - [In] byte[] buffer, - [In] int bufferSize); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - internal static extern int EnumerateSecurityPackagesW( - [Out] out int pkgnum, - [Out] out SafeFreeContextBuffer handle); - - [DllImport(SECUR32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] - internal static unsafe extern int AcquireCredentialsHandleW( - [In] string principal, - [In] string moduleName, - [In] int usage, - [In] void* logonID, - [In] ref AuthIdentity authdata, - [In] void* keyCallback, - [In] void* keyArgument, - ref SSPIHandle handlePtr, - [Out] out long timeStamp); - - [DllImport(SECUR32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] - internal static unsafe extern int AcquireCredentialsHandleW( - [In] string principal, - [In] string moduleName, - [In] int usage, - [In] void* logonID, - [In] IntPtr zero, - [In] void* keyCallback, - [In] void* keyArgument, - ref SSPIHandle handlePtr, - [Out] out long timeStamp); - - // Win7+ - [DllImport(SECUR32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] - internal static unsafe extern int AcquireCredentialsHandleW( - [In] string principal, - [In] string moduleName, - [In] int usage, - [In] void* logonID, - [In] SafeSspiAuthDataHandle authdata, - [In] void* keyCallback, - [In] void* keyArgument, - ref SSPIHandle handlePtr, - [Out] out long timeStamp); - - [DllImport(SECUR32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] - internal static unsafe extern int AcquireCredentialsHandleW( - [In] string principal, - [In] string moduleName, - [In] int usage, - [In] void* logonID, - [In] ref SecureCredential authData, - [In] void* keyCallback, - [In] void* keyArgument, - ref SSPIHandle handlePtr, - [Out] out long timeStamp); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - internal static unsafe extern int InitializeSecurityContextW( - ref SSPIHandle credentialHandle, - [In] void* inContextPtr, - [In] byte* targetName, - [In] ContextFlags inFlags, - [In] int reservedI, - [In] Endianness endianness, - [In] SecurityBufferDescriptor inputBuffer, - [In] int reservedII, - ref SSPIHandle outContextPtr, - [In, Out] SecurityBufferDescriptor outputBuffer, - [In, Out] ref ContextFlags attributes, - out long timeStamp); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - internal static unsafe extern int CompleteAuthToken( - [In] void* inContextPtr, - [In, Out] SecurityBufferDescriptor inputBuffers); - - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - internal static extern int QuerySecurityContextToken(ref SSPIHandle phContext, [Out] out SafeCloseHandle handle); - -#if ASPNETCORE50 - [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern bool CloseHandle(IntPtr handle); - -#if ASPNETCORE50 - [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif - internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); - -#if ASPNETCORE50 - [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern IntPtr LocalFree(IntPtr handle); - -#if ASPNETCORE50 - [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); - - [DllImport(CRYPT32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern void CertFreeCertificateChain( - [In] IntPtr pChainContext); - - [DllImport(CRYPT32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern void CertFreeCertificateChainList( - [In] IntPtr ppChainContext); - - [DllImport(CRYPT32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern bool CertFreeCertificateContext( // Suppressing returned status check, it's always==TRUE, - [In] IntPtr certContext); - -#if ASPNETCORE50 - [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern IntPtr GlobalFree(IntPtr handle); - } - - [System.Security.SuppressUnmanagedCodeSecurityAttribute] - internal static class NativeNTSSPI - { - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - internal static extern int EncryptMessage( - ref SSPIHandle contextHandle, - [In] uint qualityOfProtection, - [In, Out] SecurityBufferDescriptor inputOutput, - [In] uint sequenceNumber); - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - internal static unsafe extern int DecryptMessage( - [In] ref SSPIHandle contextHandle, - [In, Out] SecurityBufferDescriptor inputOutput, - [In] uint sequenceNumber, - uint* qualityOfProtection); - } // class UnsafeNclNativeMethods.NativeNTSSPI - - [SuppressUnmanagedCodeSecurityAttribute] - internal static class SspiHelper - { - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - internal static unsafe extern SecurityStatus SspiFreeAuthIdentity( - [In] IntPtr authData); - - [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage", Justification = "Implementation requires unmanaged code usage")] - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)] - internal static unsafe extern SecurityStatus SspiEncodeStringsAsAuthIdentity( - [In] string userName, - [In] string domainName, - [In] string password, - [Out] out SafeSspiAuthDataHandle authData); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs b/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs deleted file mode 100644 index 68f7b62af3..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/NegotiationInfoClass.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -namespace Microsoft.AspNet.Security.Windows -{ - using System; - using System.ComponentModel; - using System.Diagnostics; - using System.Globalization; - using System.Runtime.InteropServices; - - internal class NegotiationInfoClass - { - internal const string NTLM = "NTLM"; - internal const string Kerberos = "Kerberos"; - internal const string WDigest = "WDigest"; - internal const string Digest = "Digest"; - internal const string Negotiate = "Negotiate"; - internal string AuthenticationPackage; - - internal NegotiationInfoClass(SafeHandle safeHandle, int negotiationState) - { - if (safeHandle.IsInvalid) - { - GlobalLog.Print("NegotiationInfoClass::.ctor() the handle is invalid:" + (safeHandle.DangerousGetHandle()).ToString("x")); - return; - } - IntPtr packageInfo = safeHandle.DangerousGetHandle(); - GlobalLog.Print("NegotiationInfoClass::.ctor() packageInfo:" + packageInfo.ToString("x8") + " negotiationState:" + negotiationState.ToString("x8")); - - const int SECPKG_NEGOTIATION_COMPLETE = 0; - const int SECPKG_NEGOTIATION_OPTIMISTIC = 1; - // const int SECPKG_NEGOTIATION_IN_PROGRESS = 2; - // const int SECPKG_NEGOTIATION_DIRECT = 3; - // const int SECPKG_NEGOTIATION_TRY_MULTICRED = 4; - - if (negotiationState == SECPKG_NEGOTIATION_COMPLETE || negotiationState == SECPKG_NEGOTIATION_OPTIMISTIC) - { - IntPtr unmanagedString = Marshal.ReadIntPtr(packageInfo, SecurityPackageInfo.NameOffest); - string name = null; - if (unmanagedString != IntPtr.Zero) - { - name = Marshal.PtrToStringUni(unmanagedString); - } - GlobalLog.Print("NegotiationInfoClass::.ctor() packageInfo:" + packageInfo.ToString("x8") + " negotiationState:" + negotiationState.ToString("x8") + " name:" + ValidationHelper.ToString(name)); - - // an optimization for future string comparisons - if (string.Compare(name, Kerberos, StringComparison.OrdinalIgnoreCase) == 0) - { - AuthenticationPackage = Kerberos; - } - else if (string.Compare(name, NTLM, StringComparison.OrdinalIgnoreCase) == 0) - { - AuthenticationPackage = NTLM; - } - else if (string.Compare(name, WDigest, StringComparison.OrdinalIgnoreCase) == 0) - { - AuthenticationPackage = WDigest; - } - else - { - AuthenticationPackage = name; - } - } - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs b/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs deleted file mode 100644 index 05b2a99940..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/PrefixCollection.cs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Collections.Generic; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class PrefixCollection : ICollection - { - private WindowsAuthMiddleware _winAuth; - - internal PrefixCollection(WindowsAuthMiddleware winAuth) - { - _winAuth = winAuth; - } - - public int Count - { - get - { - return _winAuth._uriPrefixes.Count; - } - } - - public bool IsSynchronized - { - get - { - return false; - } - } - - public bool IsReadOnly - { - get - { - return false; - } - } - - public void CopyTo(Array array, int offset) - { - if (Count > array.Length) - { - throw new ArgumentOutOfRangeException("array", SR.GetString(SR.net_array_too_small)); - } - if (offset + Count > array.Length) - { - throw new ArgumentOutOfRangeException("offset"); - } - int index = 0; - foreach (string uriPrefix in _winAuth._uriPrefixes.Keys) - { - array.SetValue(uriPrefix, offset + index++); - } - } - - public void CopyTo(string[] array, int offset) - { - if (Count > array.Length) - { - throw new ArgumentOutOfRangeException("array", SR.GetString(SR.net_array_too_small)); - } - if (offset + Count > array.Length) - { - throw new ArgumentOutOfRangeException("offset"); - } - int index = 0; - foreach (string uriPrefix in _winAuth._uriPrefixes.Keys) - { - array[offset + index++] = uriPrefix; - } - } - - public void Add(string uriPrefix) - { - _winAuth.AddPrefix(uriPrefix); - } - - public bool Contains(string uriPrefix) - { - return _winAuth._uriPrefixes.Contains(uriPrefix); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return this.GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - return new PrefixEnumerator(_winAuth._uriPrefixes.Keys.GetEnumerator()); - } - - public bool Remove(string uriPrefix) - { - return _winAuth.RemovePrefix(uriPrefix); - } - - public void Clear() - { - _winAuth.RemoveAll(true); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs b/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs deleted file mode 100644 index 57adc8e236..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/PrefixEnumerator.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System.Collections; -using System.Collections.Generic; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class PrefixEnumerator : IEnumerator - { - private IEnumerator enumerator; - - internal PrefixEnumerator(IEnumerator enumerator) - { - this.enumerator = enumerator; - } - - public string Current - { - get - { - return (string)enumerator.Current; - } - } - - object System.Collections.IEnumerator.Current - { - get - { - return enumerator.Current; - } - } - - public bool MoveNext() - { - return enumerator.MoveNext(); - } - - public void Dispose() - { - } - - void System.Collections.IEnumerator.Reset() - { - enumerator.Reset(); - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs b/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs deleted file mode 100644 index 564835a6ba..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/ServiceNameStore.cs +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Net; -using System.Security.Authentication.ExtendedProtection; - -namespace Microsoft.AspNet.Security.Windows -{ - internal class ServiceNameStore - { - private List serviceNames; - private ServiceNameCollection serviceNameCollection; - - public ServiceNameStore() - { - serviceNames = new List(); - serviceNameCollection = null; // set only when needed (due to expensive item-by-item copy) - } - - public ServiceNameCollection ServiceNames - { - get - { - if (serviceNameCollection == null) - { - serviceNameCollection = new ServiceNameCollection(serviceNames); - } - return serviceNameCollection; - } - } - - private bool AddSingleServiceName(string spn) - { - spn = NormalizeServiceName(spn); - if (Contains(spn)) - { - return false; - } - else - { - serviceNames.Add(spn); - return true; - } - } - - public bool Add(string uriPrefix) - { - Debug.Assert(!String.IsNullOrEmpty(uriPrefix)); - - string[] newServiceNames = BuildServiceNames(uriPrefix); - - bool addedAny = false; - foreach (string spn in newServiceNames) - { - if (AddSingleServiceName(spn)) - { - addedAny = true; - - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, "ServiceNameStore#" + - ValidationHelper.HashString(this) + "::Add() " - + SR.GetString(SR.net_log_listener_spn_add, spn, uriPrefix)); - } - } - } - - if (addedAny) - { - serviceNameCollection = null; - } - else if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, "ServiceNameStore#" + - ValidationHelper.HashString(this) + "::Add() " - + SR.GetString(SR.net_log_listener_spn_not_add, uriPrefix)); - } - - return addedAny; - } - - public bool Remove(string uriPrefix) - { - Debug.Assert(!String.IsNullOrEmpty(uriPrefix)); - - string newServiceName = BuildSimpleServiceName(uriPrefix); - newServiceName = NormalizeServiceName(newServiceName); - bool needToRemove = Contains(newServiceName); - - if (needToRemove) - { - serviceNames.Remove(newServiceName); - serviceNameCollection = null; // invalidate (readonly) ServiceNameCollection - } - - if (Logging.On) - { - if (needToRemove) - { - Logging.PrintInfo(Logging.HttpListener, "ServiceNameStore#" + - ValidationHelper.HashString(this) + "::Remove() " - + SR.GetString(SR.net_log_listener_spn_remove, newServiceName, uriPrefix)); - } - else - { - Logging.PrintInfo(Logging.HttpListener, "ServiceNameStore#" + - ValidationHelper.HashString(this) + "::Remove() " - + SR.GetString(SR.net_log_listener_spn_not_remove, uriPrefix)); - } - } - - return needToRemove; - } - - // Assumes already normalized - private bool Contains(string newServiceName) - { - if (newServiceName == null) - { - return false; - } - - return Contains(newServiceName, serviceNames); - } - - // Assumes searchServiceName and serviceNames have already been normalized - internal static bool Contains(string searchServiceName, ICollection serviceNames) - { - Debug.Assert(serviceNames != null); - Debug.Assert(!String.IsNullOrEmpty(searchServiceName)); - - foreach (string serviceName in serviceNames) - { - if (Match(serviceName, searchServiceName)) - { - return true; - } - } - - return false; - } - - // Assumes already normalized - internal static bool Match(string serviceName1, string serviceName2) - { - return (String.Compare(serviceName1, serviceName2, StringComparison.OrdinalIgnoreCase) == 0); - } - - public void Clear() - { - serviceNames.Clear(); - serviceNameCollection = null; // invalidate (readonly) ServiceNameCollection - } - - private string ExtractHostname(string uriPrefix, bool allowInvalidUriStrings) - { - if (Uri.IsWellFormedUriString(uriPrefix, UriKind.Absolute)) - { - Uri hostUri = new Uri(uriPrefix); - return hostUri.Host; - } - else if (allowInvalidUriStrings) - { - int i = uriPrefix.IndexOf("://") + 3; - int j = i; - - bool inSquareBrackets = false; - while (j < uriPrefix.Length && uriPrefix[j] != '/' && (uriPrefix[j] != ':' || inSquareBrackets)) - { - if (uriPrefix[j] == '[') - { - if (inSquareBrackets) - { - j = i; - break; - } - inSquareBrackets = true; - } - if (inSquareBrackets && uriPrefix[j] == ']') - { - inSquareBrackets = false; - } - j++; - } - - return uriPrefix.Substring(i, j - i); - } - - return null; - } - - public string BuildSimpleServiceName(string uriPrefix) - { - string hostname = ExtractHostname(uriPrefix, false); - - if (hostname != null) - { - return "HTTP/" + hostname; - } - else - { - return null; - } - } - - public string[] BuildServiceNames(string uriPrefix) - { - string hostname = ExtractHostname(uriPrefix, true); - - IPAddress ipAddress = null; - if (String.Compare(hostname, "*", StringComparison.InvariantCultureIgnoreCase) == 0 || - String.Compare(hostname, "+", StringComparison.InvariantCultureIgnoreCase) == 0 || - IPAddress.TryParse(hostname, out ipAddress)) - { - // for a wildcard, register the machine name. If the caller doesn't have DNS permission - // or the query fails for some reason, don't add an SPN. - try - { - string machineName = Dns.GetHostEntry(String.Empty).HostName; - return new string[] { "HTTP/" + machineName }; - } - catch (System.Net.Sockets.SocketException) - { - return new string[0]; - } - catch (System.Security.SecurityException) - { - return new string[0]; - } - } - else if (!hostname.Contains(".")) - { - // for a dotless name, try to resolve the FQDN. If the caller doesn't have DNS permission - // or the query fails for some reason, add only the dotless name. - try - { - string fqdn = Dns.GetHostEntry(hostname).HostName; - return new string[] { "HTTP/" + hostname, "HTTP/" + fqdn }; - } - catch (System.Net.Sockets.SocketException) - { - return new string[] { "HTTP/" + hostname }; - } - catch (System.Security.SecurityException) - { - return new string[] { "HTTP/" + hostname }; - } - } - else - { - return new string[] { "HTTP/" + hostname }; - } - } - - // Normalizes any punycode to unicode in an Service Name (SPN) host. - // If the algorithm fails at any point then the original input is returned. - // ServiceName is in one of the following forms: - // prefix/host - // prefix/host:port - // prefix/host/DistinguishedName - // prefix/host:port/DistinguishedName - internal static string NormalizeServiceName(string inputServiceName) - { - if (string.IsNullOrWhiteSpace(inputServiceName)) - { - return inputServiceName; - } - - // Separate out the prefix - int shashIndex = inputServiceName.IndexOf('/'); - if (shashIndex < 0) - { - return inputServiceName; - } - string prefix = inputServiceName.Substring(0, shashIndex + 1); // Includes slash - string hostPortAndDistinguisher = inputServiceName.Substring(shashIndex + 1); // Excludes slash - - if (string.IsNullOrWhiteSpace(hostPortAndDistinguisher)) - { - return inputServiceName; - } - - string host = hostPortAndDistinguisher; - string port = string.Empty; - string distinguisher = string.Empty; - - // Check for the absence of a port or distinguisher. - UriHostNameType hostType = Uri.CheckHostName(hostPortAndDistinguisher); - if (hostType == UriHostNameType.Unknown) - { - string hostAndPort = hostPortAndDistinguisher; - - // Check for distinguisher - int nextSlashIndex = hostPortAndDistinguisher.IndexOf('/'); - if (nextSlashIndex >= 0) - { - // host:port/distinguisher or host/distinguisher - hostAndPort = hostPortAndDistinguisher.Substring(0, nextSlashIndex); // Excludes Slash - distinguisher = hostPortAndDistinguisher.Substring(nextSlashIndex); // Includes Slash - host = hostAndPort; // We don't know if there is a port yet. - - // No need to validate the distinguisher - } - - // Check for port - int colonIndex = hostAndPort.LastIndexOf(':'); // Allow IPv6 addresses - if (colonIndex >= 0) - { - // host:port - host = hostAndPort.Substring(0, colonIndex); // Excludes colon - port = hostAndPort.Substring(colonIndex + 1); // Excludes colon - - // Loosely validate the port just to make sure it was a port and not something else - UInt16 portValue; - if (!UInt16.TryParse(port, NumberStyles.Integer, CultureInfo.InvariantCulture, out portValue)) - { - return inputServiceName; - } - - // Re-include the colon for the final output. Do not change the port format. - port = hostAndPort.Substring(colonIndex); - } - - hostType = Uri.CheckHostName(host); // Revaidate the host - } - - if (hostType != UriHostNameType.Dns) - { - // UriHostNameType.IPv4, UriHostNameType.IPv6: Do not normalize IPv4/6 hosts. - // UriHostNameType.Basic: This is never returned by CheckHostName today - // UriHostNameType.Unknown: Nothing recognizable to normalize - // default Some new UriHostNameType? - return inputServiceName; - } - - // Now we have a valid DNS host, normalize it. - - Uri constructedUri; - // This shouldn't fail, but we need to avoid any unexpected exceptions on this code path. - if (!Uri.TryCreate(Uri.UriSchemeHttp + Uri.SchemeDelimiter + host, UriKind.Absolute, out constructedUri)) - { - return inputServiceName; - } - - string normalizedHost = constructedUri.GetComponents( - UriComponents.NormalizedHost, UriFormat.SafeUnescaped); - - string normalizedServiceName = string.Format(CultureInfo.InvariantCulture, - "{0}{1}{2}{3}", prefix, normalizedHost, port, distinguisher); - - // Don't return the new one unless we absolutely have to. It may have only changed casing. - if (String.Compare(inputServiceName, normalizedServiceName, StringComparison.OrdinalIgnoreCase) == 0) - { - return inputServiceName; - } - - return normalizedServiceName; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs b/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs deleted file mode 100644 index 9fef272e5b..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/WindowsAuthMiddleware.cs +++ /dev/null @@ -1,1298 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Net; -using System.Security.Authentication.ExtendedProtection; -using System.Security.Permissions; -using System.Security.Principal; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.AspNet.Security.Windows -{ - using AppFunc = Func, Task>; - - /// - /// A middleware that performs Windows Authentication of the specified types. - /// - public sealed class WindowsAuthMiddleware - { - private Func, AuthTypes> _authenticationDelegate; - private AuthTypes _authenticationScheme = AuthTypes.Negotiate | AuthTypes.Ntlm | AuthTypes.Digest; - private string _realm; - private PrefixCollection _prefixes; - private bool _unsafeConnectionNtlmAuthentication; - private Func, ExtendedProtectionPolicy> _extendedProtectionSelectorDelegate; - private ExtendedProtectionPolicy _extendedProtectionPolicy; - private ServiceNameStore _defaultServiceNames; - - private Hashtable _disconnectResults; // ulong -> DisconnectAsyncResult - private object _internalLock; - - internal Hashtable _uriPrefixes; - private DigestCache _digestCache; - - private AppFunc _nextApp; - - // TODO: Support proxy auth - // private bool _doProxyAuth; - - /// - /// - /// - /// - public WindowsAuthMiddleware(AppFunc nextApp) - { - if (Logging.On) - { - Logging.Enter(Logging.HttpListener, this, "WindowsAuth", string.Empty); - } - - _internalLock = new object(); - _defaultServiceNames = new ServiceNameStore(); - - // default: no CBT checks on any platform (appcompat reasons); applies also to PolicyEnforcement - // config element - _extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never); - _uriPrefixes = new Hashtable(); - _digestCache = new DigestCache(); - - _nextApp = nextApp; - - if (Logging.On) - { - Logging.Exit(Logging.HttpListener, this, "WindowsAuth", string.Empty); - } - } - - /// - /// Dynamically select the type of authentication to apply per request. - /// - public Func, AuthTypes> AuthenticationSchemeSelectorDelegate - { - get - { - return _authenticationDelegate; - } - set - { - _authenticationDelegate = value; - } - } - - /// - /// Dynamically select the type of extended protection to apply per request. - /// - public Func, ExtendedProtectionPolicy> ExtendedProtectionSelectorDelegate - { - get - { - return _extendedProtectionSelectorDelegate; - } - set - { - if (value == null) - { - throw new ArgumentNullException(); - } - - if (!ExtendedProtectionPolicy.OSSupportsExtendedProtection) - { - throw new PlatformNotSupportedException(SR.GetString(SR.security_ExtendedProtection_NoOSSupport)); - } - - _extendedProtectionSelectorDelegate = value; - } - } - - /// - /// Specifies which types of Windows authentication are enabled. - /// - public AuthTypes AuthenticationSchemes - { - get - { - return _authenticationScheme; - } - set - { - _authenticationScheme = value; - } - } - - /// - /// Configures extended protection. - /// - public ExtendedProtectionPolicy ExtendedProtectionPolicy - { - get - { - return _extendedProtectionPolicy; - } - set - { - if (value == null) - { - throw new ArgumentNullException("value"); - } - if (!ExtendedProtectionPolicy.OSSupportsExtendedProtection && value.PolicyEnforcement == PolicyEnforcement.Always) - { - throw new PlatformNotSupportedException(SR.GetString(SR.security_ExtendedProtection_NoOSSupport)); - } - if (value.CustomChannelBinding != null) - { - throw new ArgumentException(SR.GetString(SR.net_listener_cannot_set_custom_cbt), "CustomChannelBinding"); - } - - _extendedProtectionPolicy = value; - } - } - - /// - /// Configures the service names for extended protection. - /// - public ServiceNameCollection DefaultServiceNames - { - get - { - return _defaultServiceNames.ServiceNames; - } - } - - /// - /// The Realm for use in digest authentication. - /// - public string Realm - { - get - { - return _realm; - } - set - { - _realm = value; - } - } - - /// - /// Enables authenticated connection sharing with NTLM. - /// - public bool UnsafeConnectionNtlmAuthentication - { - get - { - return _unsafeConnectionNtlmAuthentication; - } - - set - { - if (_unsafeConnectionNtlmAuthentication == value) - { - return; - } - lock (DisconnectResults.SyncRoot) - { - if (_unsafeConnectionNtlmAuthentication == value) - { - return; - } - _unsafeConnectionNtlmAuthentication = value; - if (!value) - { - foreach (DisconnectAsyncResult result in DisconnectResults.Values) - { - result.AuthenticatedUser = null; - } - } - } - } - } - - internal Hashtable DisconnectResults - { - get - { - if (_disconnectResults == null) - { - Interlocked.CompareExchange(ref _disconnectResults, Hashtable.Synchronized(new Hashtable()), null); - } - return _disconnectResults; - } - } - - internal unsafe void AddPrefix(string uriPrefix) - { - if (Logging.On) - { - Logging.Enter(Logging.HttpListener, this, "AddPrefix", "uriPrefix:" + uriPrefix); - } - string registeredPrefix = null; - try - { - if (uriPrefix == null) - { - throw new ArgumentNullException("uriPrefix"); - } - (new WebPermission(NetworkAccess.Accept, uriPrefix)).Demand(); - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::AddPrefix() uriPrefix:" + uriPrefix); - int i; - if (string.Compare(uriPrefix, 0, "http://", 0, 7, StringComparison.OrdinalIgnoreCase) == 0) - { - i = 7; - } - else if (string.Compare(uriPrefix, 0, "https://", 0, 8, StringComparison.OrdinalIgnoreCase) == 0) - { - i = 8; - } - else - { - throw new ArgumentException(SR.GetString(SR.net_listener_scheme), "uriPrefix"); - } - bool inSquareBrakets = false; - int j = i; - while (j < uriPrefix.Length && uriPrefix[j] != '/' && (uriPrefix[j] != ':' || inSquareBrakets)) - { - if (uriPrefix[j] == '[') - { - if (inSquareBrakets) - { - j = i; - break; - } - inSquareBrakets = true; - } - if (inSquareBrakets && uriPrefix[j] == ']') - { - inSquareBrakets = false; - } - j++; - } - if (i == j) - { - throw new ArgumentException(SR.GetString(SR.net_listener_host), "uriPrefix"); - } - if (uriPrefix[uriPrefix.Length - 1] != '/') - { - throw new ArgumentException(SR.GetString(SR.net_listener_slash), "uriPrefix"); - } - registeredPrefix = uriPrefix[j] == ':' ? String.Copy(uriPrefix) : uriPrefix.Substring(0, j) + (i == 7 ? ":80" : ":443") + uriPrefix.Substring(j); - fixed (char* pChar = registeredPrefix) - { - i = 0; - while (pChar[i] != ':') - { - pChar[i] = (char)CaseInsensitiveAscii.AsciiToLower[(byte)pChar[i]]; - i++; - } - } - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::AddPrefix() mapped uriPrefix:" + uriPrefix + " to registeredPrefix:" + registeredPrefix); - - _uriPrefixes[uriPrefix] = registeredPrefix; - _defaultServiceNames.Add(uriPrefix); - } - catch (Exception exception) - { - if (Logging.On) - { - Logging.Exception(Logging.HttpListener, this, "AddPrefix", exception); - } - throw; - } - finally - { - if (Logging.On) - { - Logging.Exit(Logging.HttpListener, this, "AddPrefix", "prefix:" + registeredPrefix); - } - } - } - - internal PrefixCollection Prefixes - { - get - { - if (Logging.On) - { - Logging.Enter(Logging.HttpListener, this, "Prefixes_get", string.Empty); - } - if (_prefixes == null) - { - _prefixes = new PrefixCollection(this); - } - return _prefixes; - } - } - - internal bool RemovePrefix(string uriPrefix) - { - if (Logging.On) - { - Logging.Enter(Logging.HttpListener, this, "RemovePrefix", "uriPrefix:" + uriPrefix); - } - try - { - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::RemovePrefix() uriPrefix:" + uriPrefix); - if (uriPrefix == null) - { - throw new ArgumentNullException("uriPrefix"); - } - - if (!_uriPrefixes.Contains(uriPrefix)) - { - return false; - } - - _uriPrefixes.Remove(uriPrefix); - _defaultServiceNames.Remove(uriPrefix); - } - catch (Exception exception) - { - if (Logging.On) - { - Logging.Exception(Logging.HttpListener, this, "RemovePrefix", exception); - } - throw; - } - finally - { - if (Logging.On) - { - Logging.Exit(Logging.HttpListener, this, "RemovePrefix", "uriPrefix:" + uriPrefix); - } - } - return true; - } - - internal void RemoveAll(bool clear) - { - if (Logging.On) - { - Logging.Enter(Logging.HttpListener, this, "RemoveAll", string.Empty); - } - try - { - // go through the uri list and unregister for each one of them - if (_uriPrefixes.Count > 0) - { - if (clear) - { - _uriPrefixes.Clear(); - _defaultServiceNames.Clear(); - } - } - } - finally - { - if (Logging.On) - { - Logging.Exit(Logging.HttpListener, this, "RemoveAll", string.Empty); - } - } - } - - // old API, now private, and helper methods - private void Dispose(bool disposing) - { - GlobalLog.Assert(disposing, "Dispose(bool) does nothing if called from the finalizer."); - - if (!disposing) - { - return; - } - - try - { - _digestCache.Dispose(); - } - finally - { - if (Logging.On) - { - Logging.Exit(Logging.HttpListener, this, "Dispose", string.Empty); - } - } - } - - /// - /// - /// - /// - /// - public Task Invoke(IDictionary env) - { - // Process the auth header, if any - if (!TryHandleAuthentication(env)) - { - // If failed and a 400/401/500 was sent. - return Task.FromResult(null); - } - - // If passing through, register for OnSendingHeaders. Add an auth header challenge on 401. - var registerOnSendingHeaders = env.Get, object>>(Constants.ServerOnSendingHeadersKey); - if (registerOnSendingHeaders == null) - { - // This module requires OnSendingHeaders support. - throw new PlatformNotSupportedException(); - } - registerOnSendingHeaders(Set401Challenges, env); - - // Invoke the next item in the app chain - return _nextApp(env); - } - - // Returns true if auth completed successfully (or anonymous), false if there was an auth header - // but processing it failed. - private bool TryHandleAuthentication(IDictionary env) - { - DisconnectAsyncResult disconnectResult; - object connectionId = env.Get(Constants.ServerConnectionIdKey, -1); - string authorizationHeader = null; - if (!TryGetIncomingAuthHeader(env, out authorizationHeader)) - { - if (UnsafeConnectionNtlmAuthentication) - { - disconnectResult = (DisconnectAsyncResult)DisconnectResults[connectionId]; - if (disconnectResult != null) - { - WindowsPrincipal principal = disconnectResult.AuthenticatedUser; - if (principal != null) - { - // This connection has already been authenticated; - SetIdentity(env, principal, null); - } - } - } - - return true; // Anonymous or UnsafeConnectionNtlmAuthentication - } - - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() authorizationHeader:" + ValidationHelper.ToString(authorizationHeader)); - - if (UnsafeConnectionNtlmAuthentication) - { - disconnectResult = (DisconnectAsyncResult)DisconnectResults[connectionId]; - // They sent an authorization header - destroy their previous credentials. - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() clearing principal cache"); - if (disconnectResult != null) - { - disconnectResult.AuthenticatedUser = null; - } - } - - try - { - AuthTypes headerScheme; - string inBlob; - if (!TryGetRecognizedAuthScheme(authorizationHeader, out headerScheme, out inBlob)) - { - return true; // Anonymous / pass through - } - Contract.Assert(headerScheme != AuthTypes.None); - Contract.Assert(inBlob != null); - - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() Performing Authentication headerScheme:" + ValidationHelper.ToString(headerScheme)); - switch (headerScheme) - { - case AuthTypes.Digest: - return TryAuthenticateWithDigest(env, inBlob); - - case AuthTypes.Negotiate: - case AuthTypes.Ntlm: - string package = headerScheme == AuthTypes.Ntlm ? NegotiationInfoClass.NTLM : NegotiationInfoClass.Negotiate; - return TryAuthenticateWithNegotiate(env, package, inBlob); - - default: - throw new NotImplementedException(headerScheme.ToString()); - } - } - catch (Exception) - { - SendError(env, HttpStatusCode.InternalServerError, null); - return false; - } - } - - // TODO: Support proxy auth - private bool TryGetIncomingAuthHeader(IDictionary env, out string authorizationHeader) - { - IDictionary headers = env.Get>(Constants.RequestHeadersKey); - authorizationHeader = headers.Get("Authorization"); - return !string.IsNullOrWhiteSpace(authorizationHeader); - } - - private bool TryGetRecognizedAuthScheme(string authorizationHeader, out AuthTypes headerScheme, out string inBlob) - { - headerScheme = AuthTypes.None; - - int index; - // Find the end of the scheme name. Trust that HTTP.SYS parsed out just our header ok. - for (index = 0; index < authorizationHeader.Length; index++) - { - if (authorizationHeader[index] == ' ' || authorizationHeader[index] == '\t' || - authorizationHeader[index] == '\r' || authorizationHeader[index] == '\n') - { - break; - } - } - - // Currently only allow one Authorization scheme/header per request. - if (index < authorizationHeader.Length) - { - if ((AuthenticationSchemes & AuthTypes.Negotiate) != AuthTypes.None && - string.Compare(authorizationHeader, 0, NegotiationInfoClass.Negotiate, 0, index, StringComparison.OrdinalIgnoreCase) == 0) - { - headerScheme = AuthTypes.Negotiate; - } - else if ((AuthenticationSchemes & AuthTypes.Ntlm) != AuthTypes.None && - string.Compare(authorizationHeader, 0, NegotiationInfoClass.NTLM, 0, index, StringComparison.OrdinalIgnoreCase) == 0) - { - headerScheme = AuthTypes.Ntlm; - } - else if ((AuthenticationSchemes & AuthTypes.Digest) != AuthTypes.None && - string.Compare(authorizationHeader, 0, NegotiationInfoClass.Digest, 0, index, StringComparison.OrdinalIgnoreCase) == 0) - { - headerScheme = AuthTypes.Digest; - } - } - - // Find the beginning of the blob. Trust that HTTP.SYS parsed out just our header ok. - for (index++; index < authorizationHeader.Length; index++) - { - if (authorizationHeader[index] != ' ' && authorizationHeader[index] != '\t' && - authorizationHeader[index] != '\r' && authorizationHeader[index] != '\n') - { - break; - } - } - inBlob = index < authorizationHeader.Length ? authorizationHeader.Substring(index) : string.Empty; - - return headerScheme != AuthTypes.None; - } - - // Returns true if successfully authenticated via Digest. Returns false if a 401 was sent. - private bool TryAuthenticateWithDigest(IDictionary env, string inBlob) - { - NTAuthentication context = null; - IPrincipal principal = null; - SecurityStatus statusCodeNew; - ChannelBinding binding; - string outBlob; - HttpStatusCode httpError = HttpStatusCode.OK; - string verb = env.Get(Constants.RequestMethodKey); - bool isSecureConnection = IsSecureConnection(env); - // GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() package:WDigest headerScheme:" + headerScheme); - - // WDigest had some weird behavior. This is what I have discovered: - // Local accounts don't work, only domain accounts. The domain (i.e. REDMOND) is implied. Not sure how it is chosen. - // If the domain is specified and the credentials are correct, it works. If they're not (domain, username or password): - // AcceptSecurityContext (GetOutgoingDigestBlob) returns success but with a bogus 4k challenge, and - // QuerySecurityContextToken (GetContextToken) fails with NoImpersonation. - // If the domain isn't specified, AcceptSecurityContext returns NoAuthenticatingAuthority for a bad username, - // and LogonDenied for a bad password. - - // Also interesting is that WDigest requires us to keep a reference to the previous context, but fails if we - // actually pass it in! (It't ok to pass it in for the first request, but not if nc > 1.) For Whidbey, - // we create a new context and associate it with the connection, just like NTLM, but instead of using it for - // the next request on the connection, we always create a new context and swap the old one out. As long - // as we keep the old one around until after we authenticate with the new one, it works. For this reason, - // we also keep these contexts around past the lifetime of the connection, so that KeepAlive=false works. - binding = GetChannelBinding(env, isSecureConnection, ExtendedProtectionPolicy); - - context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null, - GetContextFlags(ExtendedProtectionPolicy, isSecureConnection), binding); - - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() verb:" + verb + " context.IsValidContext:" + context.IsValidContext.ToString()); - - outBlob = context.GetOutgoingDigestBlob(inBlob, verb, null, Realm, false, false, out statusCodeNew); - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew + " outBlob:[" + outBlob + "]"); - - // WDigest bug: sometimes when AcceptSecurityContext returns success, it provides a bogus, empty 4k buffer. - // Ignore it. (Should find out what's going on here from WDigest people.) - if (statusCodeNew == SecurityStatus.OK) - { - outBlob = null; - } - - IList challenges = null; - if (outBlob != null) - { - string challenge = NegotiationInfoClass.Digest + " " + outBlob; - AddChallenge(ref challenges, challenge); - } - - if (context.IsValidContext) - { - SafeCloseHandle userContext = null; - try - { - if (!CheckSpn(context, isSecureConnection, ExtendedProtectionPolicy)) - { - httpError = HttpStatusCode.Unauthorized; - } - else - { - SetServiceName(env, context.ClientSpecifiedSpn); - - userContext = context.GetContextToken(out statusCodeNew); - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() returned:" + statusCodeNew.ToString()); - if (statusCodeNew != SecurityStatus.OK) - { - httpError = HttpStatusFromSecurityStatus(statusCodeNew); - } - else if (userContext == null) - { - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() error: GetContextToken() returned:null statusCodeNew:" + statusCodeNew.ToString()); - httpError = HttpStatusCode.Unauthorized; - } - else - { - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8")); - principal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), "Digest"/*DigestClient.AuthType*/, WindowsAccountType.Normal, true)); - SetIdentity(env, principal, null); - _digestCache.SaveDigestContext(context); - } - } - } - finally - { - if (userContext != null) - { - userContext.Dispose(); - } - } - } - else - { - httpError = HttpStatusFromSecurityStatus(statusCodeNew); - } - - if (httpError != HttpStatusCode.OK) - { - SendError(env, httpError, challenges); - return false; - } - return true; - } - - // Negotiate or NTLM - private bool TryAuthenticateWithNegotiate(IDictionary env, string package, string inBlob) - { - object connectionId = env.Get(Constants.ServerConnectionIdKey, null); - if (connectionId == null) - { - // We need a connection ID from the server to correctly track in-progress auth. - throw new PlatformNotSupportedException(); - } - - NTAuthentication oldContext = null, context; - DisconnectAsyncResult disconnectResult = (DisconnectAsyncResult)DisconnectResults[connectionId]; - if (disconnectResult != null) - { - oldContext = disconnectResult.Session; - } - ChannelBinding binding; - bool isSecureConnection = IsSecureConnection(env); - byte[] bytes = null; - HttpStatusCode httpError = HttpStatusCode.OK; - bool error = false; - string outBlob = null; - - if (oldContext != null && oldContext.Package == package) - { - context = oldContext; - } - else - { - binding = GetChannelBinding(env, isSecureConnection, ExtendedProtectionPolicy); - - context = new NTAuthentication(true, package, null, - GetContextFlags(ExtendedProtectionPolicy, isSecureConnection), binding); - - // Clean up old context - if (oldContext != null) - { - oldContext.CloseContext(); - } - } - - try - { - bytes = Convert.FromBase64String(inBlob); - } - catch (FormatException) - { - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() FromBase64String threw a FormatException."); - httpError = HttpStatusCode.BadRequest; - error = true; - } - - byte[] decodedOutgoingBlob = null; - SecurityStatus statusCodeNew; - if (!error) - { - decodedOutgoingBlob = context.GetOutgoingBlob(bytes, false, out statusCodeNew); - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew); - error = !context.IsValidContext; - if (error) - { - // Bug #474228: SSPI Workaround - // If a client sends up a blob on the initial request, Negotiate returns SEC_E_INVALID_HANDLE - // when it should return SEC_E_INVALID_TOKEN. - if (statusCodeNew == SecurityStatus.InvalidHandle && oldContext == null && bytes != null && bytes.Length > 0) - { - statusCodeNew = SecurityStatus.InvalidToken; - } - - httpError = HttpStatusFromSecurityStatus(statusCodeNew); - } - } - - if (decodedOutgoingBlob != null) - { - outBlob = Convert.ToBase64String(decodedOutgoingBlob); - } - - if (!error) - { - if (context.IsCompleted) - { - SafeCloseHandle userContext = null; - try - { - if (!CheckSpn(context, isSecureConnection, ExtendedProtectionPolicy)) - { - httpError = HttpStatusCode.Unauthorized; - } - else - { - SetServiceName(env, context.ClientSpecifiedSpn); - - userContext = context.GetContextToken(out statusCodeNew); - if (statusCodeNew != SecurityStatus.OK) - { - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() failed with statusCodeNew:" + statusCodeNew.ToString()); - httpError = HttpStatusFromSecurityStatus(statusCodeNew); - } - else - { - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8")); - WindowsPrincipal windowsPrincipal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), context.ProtocolName, WindowsAccountType.Normal, true)); - SetIdentity(env, windowsPrincipal, outBlob); - - // if appropriate, cache this credential on this connection - if (UnsafeConnectionNtlmAuthentication - && context.ProtocolName.Equals(NegotiationInfoClass.NTLM, StringComparison.OrdinalIgnoreCase)) - { - // We may need to call WaitForDisconnect. - if (disconnectResult == null) - { - RegisterForDisconnectNotification(env, out disconnectResult); - } - - if (disconnectResult != null) - { - lock (DisconnectResults.SyncRoot) - { - if (UnsafeConnectionNtlmAuthentication) - { - disconnectResult.AuthenticatedUser = windowsPrincipal; - } - } - } - } - } - } - } - finally - { - if (userContext != null) - { - userContext.Dispose(); - } - } - return true; - } - else - { - // auth incomplete - if (disconnectResult == null) - { - RegisterForDisconnectNotification(env, out disconnectResult); - - // Failed - send 500. - if (disconnectResult == null) - { - context.CloseContext(); - SendError(env, HttpStatusCode.InternalServerError, null); - return false; - } - } - - disconnectResult.Session = context; - - string challenge = package; - if (!String.IsNullOrEmpty(outBlob)) - { - challenge += " " + outBlob; - } - IList challenges = null; - AddChallenge(ref challenges, challenge); - SendError(env, HttpStatusCode.Unauthorized, challenges); - return false; - } - } - - SendError(env, httpError, null); - return false; - } - - private void SetIdentity(IDictionary env, IPrincipal principal, string mutualAuth) - { - env[Constants.ServerUserKey] = principal; - if (!string.IsNullOrWhiteSpace(mutualAuth)) - { - var responseHeaders = env.Get>(Constants.ResponseHeadersKey); - responseHeaders.Append(HttpKnownHeaderNames.WWWAuthenticate, mutualAuth); - } - } - - // For user info only - private void SetServiceName(IDictionary env, string serviceName) - { - if (!string.IsNullOrWhiteSpace(serviceName)) - { - env[Constants.SslSpnKey] = serviceName; - } - } - - [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)] - [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)] - internal static WindowsIdentity CreateWindowsIdentity(IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated) - { - return new WindowsIdentity(userToken, type, acctType, isAuthenticated); - } - - // On a 401 response, set any appropriate challenges - private void Set401Challenges(object state) - { - var env = (IDictionary)state; - var responseHeaders = env.Get>(Constants.ResponseHeadersKey); - - // We use the cached results from the delegates so that we don't have to call them again here. - NTAuthentication newContext; - IList challenges = BuildChallenge(env, AuthenticationSchemes, out newContext, ExtendedProtectionPolicy); - - // null == Anonymous - if (challenges != null) - { - // Digest challenge, keep it alive for 10s - 5min. - if (newContext != null) - { - _digestCache.SaveDigestContext(newContext); - } - - responseHeaders.Append(HttpKnownHeaderNames.WWWAuthenticate, challenges); - } - } - - private static bool IsSecureConnection(IDictionary env) - { - return "https".Equals(env.Get(Constants.RequestSchemeKey, "http"), StringComparison.OrdinalIgnoreCase); - } - - private static bool ScenarioChecksChannelBinding(bool isSecureConnection, ProtectionScenario scenario) - { - return (isSecureConnection && scenario == ProtectionScenario.TransportSelected); - } - - private ChannelBinding GetChannelBinding(IDictionary env, bool isSecureConnection, ExtendedProtectionPolicy policy) - { - if (policy.PolicyEnforcement == PolicyEnforcement.Never) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_cbt_disabled)); - } - return null; - } - - if (!isSecureConnection) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_cbt_http)); - } - return null; - } - - if (!ExtendedProtectionPolicy.OSSupportsExtendedProtection) - { - GlobalLog.Assert(policy.PolicyEnforcement != PolicyEnforcement.Always, "User managed to set PolicyEnforcement.Always when the OS does not support extended protection!"); - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_cbt_platform)); - } - return null; - } - - if (policy.ProtectionScenario == ProtectionScenario.TrustedProxy) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_cbt_trustedproxy)); - } - return null; - } - - ChannelBinding result = env.Get(Constants.SslChannelBindingKey); - if (result == null) - { - // A channel binding object is required. - throw new InvalidOperationException(); - } - - GlobalLog.Assert(result != null, "GetChannelBindingFromTls returned null even though OS supposedly supports Extended Protection"); - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_cbt)); - } - return result; - } - - private bool CheckSpn(NTAuthentication context, bool isSecureConnection, ExtendedProtectionPolicy policy) - { - // Kerberos does SPN check already in ASC - if (context.IsKerberos) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_kerberos)); - } - return true; - } - - // Don't check the SPN if Extended Protection is off or we already checked the CBT - if (policy.PolicyEnforcement == PolicyEnforcement.Never) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_disabled)); - } - return true; - } - - if (ScenarioChecksChannelBinding(isSecureConnection, policy.ProtectionScenario)) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_cbt)); - } - return true; - } - - if (!ExtendedProtectionPolicy.OSSupportsExtendedProtection) - { - GlobalLog.Assert(policy.PolicyEnforcement != PolicyEnforcement.Always, "User managed to set PolicyEnforcement.Always when the OS does not support extended protection!"); - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_platform)); - } - return true; - } - - string clientSpn = context.ClientSpecifiedSpn; - - // An empty SPN is only allowed in the WhenSupported case - if (String.IsNullOrEmpty(clientSpn)) - { - if (policy.PolicyEnforcement == PolicyEnforcement.WhenSupported) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, - SR.GetString(SR.net_log_listener_no_spn_whensupported)); - } - return true; - } - else - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, - SR.GetString(SR.net_log_listener_spn_failed_always)); - } - return false; - } - } - else if (String.Compare(clientSpn, "http/localhost", StringComparison.OrdinalIgnoreCase) == 0) - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_no_spn_loopback)); - } - - return true; - } - else - { - if (Logging.On) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_spn, clientSpn)); - } - - ServiceNameCollection serviceNames = GetServiceNames(policy); - - bool found = serviceNames.Contains(clientSpn); - - if (Logging.On) - { - if (found) - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_spn_passed)); - } - else - { - Logging.PrintInfo(Logging.HttpListener, this, SR.GetString(SR.net_log_listener_spn_failed)); - - if (serviceNames.Count == 0) - { - Logging.PrintWarning(Logging.HttpListener, this, "CheckSpn", - SR.GetString(SR.net_log_listener_spn_failed_empty)); - } - else - { - Logging.PrintInfo(Logging.HttpListener, this, - SR.GetString(SR.net_log_listener_spn_failed_dump)); - - foreach (string serviceName in serviceNames) - { - Logging.PrintInfo(Logging.HttpListener, this, "\t" + serviceName); - } - } - } - } - - return found; - } - } - - private ServiceNameCollection GetServiceNames(ExtendedProtectionPolicy policy) - { - ServiceNameCollection serviceNames; - - if (policy.CustomServiceNames == null) - { - if (_defaultServiceNames.ServiceNames.Count == 0) - { - throw new InvalidOperationException(SR.GetString(SR.net_listener_no_spns)); - } - serviceNames = _defaultServiceNames.ServiceNames; - } - else - { - serviceNames = policy.CustomServiceNames; - } - return serviceNames; - } - - private ContextFlags GetContextFlags(ExtendedProtectionPolicy policy, bool isSecureConnection) - { - ContextFlags result = ContextFlags.Connection; - - if (policy.PolicyEnforcement != PolicyEnforcement.Never) - { - if (policy.PolicyEnforcement == PolicyEnforcement.WhenSupported) - { - result |= ContextFlags.AllowMissingBindings; - } - - if (policy.ProtectionScenario == ProtectionScenario.TrustedProxy) - { - result |= ContextFlags.ProxyBindings; - } - } - - return result; - } - - private static void AddChallenge(ref IList challenges, string challenge) - { - if (challenge != null) - { - challenge = challenge.Trim(); - if (challenge.Length > 0) - { - GlobalLog.Print("HttpListener:AddChallenge() challenge:" + challenge); - if (challenges == null) - { - challenges = new List(4); - } - challenges.Add(challenge); - } - } - } - - private IList BuildChallenge(IDictionary env, AuthTypes authenticationScheme, out NTAuthentication digestContext, - ExtendedProtectionPolicy policy) - { - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() authenticationScheme:" + authenticationScheme.ToString()); - IList challenges = null; - digestContext = null; - - if ((authenticationScheme & AuthTypes.Negotiate) != 0) - { - AddChallenge(ref challenges, NegotiationInfoClass.Negotiate); - } - - if ((authenticationScheme & AuthTypes.Ntlm) != 0) - { - AddChallenge(ref challenges, NegotiationInfoClass.NTLM); - } - - if ((authenticationScheme & AuthTypes.Digest) != 0) - { - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() package:WDigest"); - - NTAuthentication context = null; - try - { - bool isSecureConnection = IsSecureConnection(env); - string outBlob = null; - ChannelBinding binding = GetChannelBinding(env, isSecureConnection, policy); - - context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null, - GetContextFlags(policy, isSecureConnection), binding); - - SecurityStatus statusCode; - outBlob = context.GetOutgoingDigestBlob(null, null, null, Realm, false, false, out statusCode); - GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCode:" + statusCode + " outBlob:[" + outBlob + "]"); - - if (context.IsValidContext) - { - digestContext = context; - _digestCache.SaveDigestContext(digestContext); - } - - AddChallenge(ref challenges, NegotiationInfoClass.Digest + (string.IsNullOrEmpty(outBlob) ? string.Empty : " " + outBlob)); - } - catch (InvalidOperationException) - { - // No CBT available, therefore no digest challenge can be issued. - } - finally - { - if (context != null && digestContext != context) - { - context.CloseContext(); - } - } - } - - return challenges; - } - - private void RegisterForDisconnectNotification(IDictionary env, out DisconnectAsyncResult disconnectResult) - { - object connectionId = env[Constants.ServerConnectionIdKey]; - CancellationToken connectionDisconnect = env.Get(Constants.ServerConnectionDisconnectKey); - if (!connectionDisconnect.CanBeCanceled || connectionDisconnect.IsCancellationRequested) - { - disconnectResult = null; - return; - } - try - { - disconnectResult = new DisconnectAsyncResult(this, connectionId, connectionDisconnect); - } - catch (ObjectDisposedException) - { - // Just disconnected - disconnectResult = null; - return; - } - } - - private void SendError(IDictionary env, HttpStatusCode httpStatusCode, IList challenges) - { - // Send an OWIN HTTP response with the given error status code. - env[Constants.ResponseStatusCodeKey] = (int)httpStatusCode; - - if (challenges != null) - { - var responseHeaders = env.Get>(Constants.ResponseHeadersKey); - responseHeaders.Append(HttpKnownHeaderNames.WWWAuthenticate, challenges); - } - } - - // This only works for context-destroying errors. - private HttpStatusCode HttpStatusFromSecurityStatus(SecurityStatus status) - { - if (IsCredentialFailure(status)) - { - return HttpStatusCode.Unauthorized; - } - if (IsClientFault(status)) - { - return HttpStatusCode.BadRequest; - } - return HttpStatusCode.InternalServerError; - } - - // This only works for context-destroying errors. - private static bool IsCredentialFailure(SecurityStatus error) - { - return error == SecurityStatus.LogonDenied || - error == SecurityStatus.UnknownCredentials || - error == SecurityStatus.NoImpersonation || - error == SecurityStatus.NoAuthenticatingAuthority || - error == SecurityStatus.UntrustedRoot || - error == SecurityStatus.CertExpired || - error == SecurityStatus.SmartcardLogonRequired || - error == SecurityStatus.BadBinding; - } - - // This only works for context-destroying errors. - private static bool IsClientFault(SecurityStatus error) - { - return error == SecurityStatus.InvalidToken || - error == SecurityStatus.CannotPack || - error == SecurityStatus.QopNotSupported || - error == SecurityStatus.NoCredentials || - error == SecurityStatus.MessageAltered || - error == SecurityStatus.OutOfSequence || - error == SecurityStatus.IncompleteMessage || - error == SecurityStatus.IncompleteCredentials || - error == SecurityStatus.WrongPrincipal || - error == SecurityStatus.TimeSkew || - error == SecurityStatus.IllegalMessage || - error == SecurityStatus.CertUnknown || - error == SecurityStatus.AlgorithmMismatch || - error == SecurityStatus.SecurityQosFailed || - error == SecurityStatus.UnsupportedPreauth; - } - } -} diff --git a/src/Microsoft.AspNet.Security.Windows/project.json b/src/Microsoft.AspNet.Security.Windows/project.json deleted file mode 100644 index 710de00f3a..0000000000 --- a/src/Microsoft.AspNet.Security.Windows/project.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": "1.0.0-*", - "dependencies": { - }, - "compilationOptions" : { "allowUnsafe": true }, - "frameworks": - { - "aspnet50" : { - "dependencies": { - } - } - } -} From c6357bd2f679917ca2e0368792603e3bc91f1118 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 1 Oct 2014 14:51:46 -0700 Subject: [PATCH 121/597] Removing declaration expressions --- .../ServerTests.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index e66e1f768e..12e9282073 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -17,7 +17,8 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_200OK_Success() { - using (var server = Utilities.CreateHttpServer(out var address)) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { var responseTask = SendRequestAsync(address); @@ -32,7 +33,8 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_SendHelloWorld_Success() { - using (var server = Utilities.CreateHttpServer(out var address)) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { Task responseTask = SendRequestAsync(address); @@ -51,7 +53,8 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_EchoHelloWorld_Success() { - using (var server = Utilities.CreateHttpServer(out var address)) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { var responseTask = SendRequestAsync(address, "Hello World"); @@ -75,7 +78,8 @@ namespace Microsoft.Net.Http.Server var interval = TimeSpan.FromSeconds(1); var canceled = new ManualResetEvent(false); - using (var server = Utilities.CreateHttpServer(out var address)) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { using (var client = new HttpClient()) { @@ -105,7 +109,8 @@ namespace Microsoft.Net.Http.Server var interval = TimeSpan.FromSeconds(1); var canceled = new ManualResetEvent(false); - using (var server = Utilities.CreateHttpServer(out var address)) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { var responseTask = SendRequestAsync(address); @@ -132,7 +137,8 @@ namespace Microsoft.Net.Http.Server var interval = TimeSpan.FromSeconds(1); var canceled = new ManualResetEvent(false); - using (var server = Utilities.CreateHttpServer(out var address)) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { var responseTask = SendRequestAsync(address); @@ -161,7 +167,8 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task Server_SetQueueLimit_Success() { - using (var server = Utilities.CreateHttpServer(out var address)) + string address; + using (var server = Utilities.CreateHttpServer(out address)) { server.SetRequestQueueLimit(1001); var responseTask = SendRequestAsync(address); From 4350866536b011c53795ba182fd0353646253273 Mon Sep 17 00:00:00 2001 From: jhawk42 Date: Wed, 1 Oct 2014 12:27:14 -0700 Subject: [PATCH 122/597] change-to-libraryloader-l1-1-0 --- .../NativeInterop/UnsafeNativeMethods.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index 3d005ba6b7..262f327bc1 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -37,7 +37,7 @@ namespace Microsoft.Net.Http.Server private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-1.dll"; private const string api_ms_win_core_handle_LIB = "api-ms-win-core-handle-l1-1-0.dll"; - private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-1.dll"; + private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll"; private const string api_ms_win_core_heap_obsolete_LIB = "api-ms-win-core-heap-obsolete-L1-1-0.dll"; private const string api_ms_win_core_kernel32_legacy_LIB = "api-ms-win-core-kernel32-legacy-l1-1-0.dll"; #else diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs index f522002f8b..52de2495d6 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -32,7 +32,7 @@ namespace Microsoft.Net.WebSockets internal static class UnsafeNativeMethods { #if ASPNETCORE50 - private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-1.dll"; + private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll"; #else private const string KERNEL32 = "kernel32.dll"; #endif From 8bbf5db1ac6d431f07311463dcfbbfc76adf53d2 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 2 Oct 2014 15:51:30 -0700 Subject: [PATCH 123/597] #69 - Make WebListener target Net45. --- .../AuthenticationManager.cs | 12 ++++---- .../NativeInterop/ComNetOS.cs | 7 +++-- .../NativeInterop/HttpSysSettings.cs | 6 ++-- .../NativeInterop/NclUtilities.cs | 2 +- .../RequestProcessing/OpaqueStream.cs | 4 +-- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestStream.cs | 26 ++++++++-------- .../RequestProcessing/RequestUriBuilder.cs | 6 ++-- .../RequestProcessing/Response.cs | 6 ++-- .../RequestProcessing/ResponseStream.cs | 14 ++++----- .../ResponseStreamAsyncResult.cs | 6 ++-- .../TimeoutManager.cs | 8 ++--- src/Microsoft.Net.Http.Server/WebListener.cs | 30 +++++++++---------- .../WebListenerException.cs | 6 ++-- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 2 +- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 2 +- .../fx/System/Diagnostics/TraceEventType.cs | 2 +- .../fx/System/ExternDll.cs | 6 +--- .../InteropServices/ExternalException.cs | 2 +- .../fx/System/SafeNativeMethods.cs | 6 +--- src/Microsoft.Net.Http.Server/project.json | 3 +- .../NativeInterop/SafeNativeOverlapped.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 6 ++-- src/Microsoft.Net.WebSockets/WebSocketBase.cs | 10 +++---- .../WebSocketBuffer.cs | 8 ++--- .../WebSocketException.cs | 2 +- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 2 +- .../fx/System/AccessViolationException.cs | 2 +- .../System/ComponentModel/Win32Exception.cs | 2 +- .../fx/System/ExternDll.cs | 6 +--- .../InteropServices/ExternalException.cs | 2 +- .../fx/System/SafeNativeMethods.cs | 6 +--- .../fx/System/SystemException.cs | 2 +- src/Microsoft.Net.WebSockets/project.json | 2 +- .../RequestBodyTests.cs | 2 +- .../project.json | 28 ++++++++--------- 36 files changed, 113 insertions(+), 127 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 4dd506ba29..26670dfa48 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -39,12 +39,12 @@ namespace Microsoft.Net.Http.Server /// public sealed class AuthenticationManager { -#if ASPNET50 - private static readonly int AuthInfoSize = - Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO)); -#else +#if ASPNETCORE50 private static readonly int AuthInfoSize = Marshal.SizeOf(); +#else + private static readonly int AuthInfoSize = + Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO)); #endif private WebListener _server; @@ -163,7 +163,7 @@ namespace Microsoft.Net.Http.Server && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { -#if ASPNET50 +#if !ASPNETCORE50 return true; #endif } @@ -176,7 +176,7 @@ namespace Microsoft.Net.Http.Server && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { -#if ASPNET50 +#if !ASPNETCORE50 return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken, GetAuthTypeFromRequest(requestInfo->pInfo->AuthType).ToString())); #endif diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index ff8c54aa99..030b152caa 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -32,11 +32,12 @@ namespace Microsoft.Net.Http.Server static ComNetOS() { -#if ASPNET50 +#if ASPNETCORE50 + // TODO: SkipIOCPCallbackOnSuccess doesn't work on Win7. Need a way to detect Win7 vs 8+. + IsWin8orLater = false; +#else var win8Version = new Version(6, 2); IsWin8orLater = (Environment.OSVersion.Version >= win8Version); -#else - IsWin8orLater = true; #endif } } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs index f55d833576..1d6daab69d 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Security; -#if ASPNET50 +#if !ASPNETCORE50 using Microsoft.Win32; #endif @@ -34,7 +34,7 @@ namespace Microsoft.Net.Http.Server { internal static class HttpSysSettings { -#if ASPNET50 +#if !ASPNETCORE50 private const string HttpSysParametersKey = @"System\CurrentControlSet\Services\HTTP\Parameters"; #endif private const bool EnableNonUtf8Default = true; @@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server } private static void ReadHttpSysRegistrySettings() -#if !ASPNET50 +#if ASPNETCORE50 { } #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs index c3aaec9cb7..2e6d3c4b07 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server get { return Environment.HasShutdownStarted -#if ASPNET50 +#if !ASPNETCORE50 || AppDomain.CurrentDomain.IsFinalizingForUnload() #endif ; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs index 54215adb62..9d6ab5bf03 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs @@ -109,7 +109,7 @@ namespace Microsoft.Net.Http.Server { return _requestStream.ReadByte(); } -#if ASPNET50 +#if !ASPNETCORE50 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _requestStream.BeginRead(buffer, offset, count, callback, state); @@ -143,7 +143,7 @@ namespace Microsoft.Net.Http.Server { _responseStream.WriteByte(value); } -#if ASPNET50 +#if !ASPNETCORE50 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _responseStream.BeginWrite(buffer, offset, count, callback, state); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 3d03cbc366..015cb98e47 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -29,7 +29,7 @@ using System.Net; using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; -#if ASPNET50 +#if !ASPNETCORE50 using System.Security.Principal; #endif using System.Threading; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 0beaf04cda..cbeaa2fb70 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -198,10 +198,10 @@ namespace Microsoft.Net.Http.Server } } -#if ASPNET50 - public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) -#else +#if ASPNETCORE50 public unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#else + public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #endif { ValidateReadBuffer(buffer, offset, size); @@ -291,10 +291,10 @@ namespace Microsoft.Net.Http.Server return asyncResult; } -#if ASPNET50 - public override int EndRead(IAsyncResult asyncResult) -#else +#if ASPNETCORE50 public int EndRead(IAsyncResult asyncResult) +#else + public override int EndRead(IAsyncResult asyncResult) #endif { if (asyncResult == null) @@ -425,20 +425,20 @@ namespace Microsoft.Net.Http.Server { throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } - -#if ASPNET50 - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) -#else + +#if ASPNETCORE50 public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#else + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #endif { throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if ASPNET50 - public override void EndWrite(IAsyncResult asyncResult) -#else +#if ASPNETCORE50 public void EndWrite(IAsyncResult asyncResult) +#else + public override void EndWrite(IAsyncResult asyncResult) #endif { throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 0da68b19bc..a9301ea464 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -70,10 +70,10 @@ namespace Microsoft.Net.Http.Server // TODO: False triggers more detailed/correct parsing, but it's rather slow. UseCookedRequestUrl = true; // SettingsSectionInternal.Section.HttpListenerUnescapeRequestUrl; Utf8Encoding = new UTF8Encoding(false, true); -#if ASPNET50 - AnsiEncoding = Encoding.GetEncoding(0, new EncoderExceptionFallback(), new DecoderExceptionFallback()); -#else +#if ASPNETCORE50 AnsiEncoding = Utf8Encoding; +#else + AnsiEncoding = Encoding.GetEncoding(0, new EncoderExceptionFallback(), new DecoderExceptionFallback()); #endif } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index b85010f985..72aa46bd8c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -702,10 +702,10 @@ namespace Microsoft.Net.Http.Server knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = -#if ASPNET50 - (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); -#else +#if ASPNETCORE50 (uint)Marshal.SizeOf(); +#else + (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); #endif UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 94c20b00d1..5572e22e5a 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -195,7 +195,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } -#if ASPNET50 +#if !ASPNETCORE50 public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); @@ -360,10 +360,10 @@ namespace Microsoft.Net.Http.Server // TODO: Verbose log data written } -#if ASPNET50 - public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) -#else +#if ASPNETCORE50 public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) +#else + public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #endif { if (buffer == null) @@ -465,10 +465,10 @@ namespace Microsoft.Net.Http.Server return asyncResult; } -#if ASPNET50 - public override void EndWrite(IAsyncResult asyncResult) -#else +#if ASPNETCORE50 public void EndWrite(IAsyncResult asyncResult) +#else + public override void EndWrite(IAsyncResult asyncResult) #endif { if (asyncResult == null) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index d1dfc1bb9e..c7b71d2aed 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -140,12 +140,12 @@ namespace Microsoft.Net.Http.Server overlapped.AsyncResult = this; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. -#if ASPNET50 +#if ASPNETCORE50 + _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. +#else // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive. -#else - _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. #endif long length = _fileStream.Length; // Expensive if (offset < 0 || offset > length) diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index 53f819d99b..29160fe402 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -35,12 +35,12 @@ namespace Microsoft.Net.Http.Server /// public sealed class TimeoutManager { -#if ASPNET50 - private static readonly int TimeoutLimitSize = - Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO)); -#else +#if ASPNETCORE50 private static readonly int TimeoutLimitSize = Marshal.SizeOf(); +#else + private static readonly int TimeoutLimitSize = + Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO)); #endif private WebListener _server; private int[] _timeouts; diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 11288670c3..70755ec5d3 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -44,17 +44,17 @@ namespace Microsoft.Net.Http.Server public sealed class WebListener : IDisposable { private const long DefaultRequestQueueLength = 1000; // Http.sys default. -#if ASPNET50 +#if ASPNETCORE50 + private static readonly int RequestChannelBindStatusSize = + Marshal.SizeOf(); + private static readonly int BindingInfoSize = + Marshal.SizeOf(); +#else private static readonly Type ChannelBindingStatusType = typeof(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS); private static readonly int RequestChannelBindStatusSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS)); private static readonly int BindingInfoSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO)); -#else - private static readonly int RequestChannelBindStatusSize = - Marshal.SizeOf(); - private static readonly int BindingInfoSize = - Marshal.SizeOf(); #endif // Win8# 559317 fixed a bug in Http.sys's HttpReceiveClientCertificate method. @@ -819,10 +819,10 @@ namespace Microsoft.Net.Http.Server knownHeaderInfo[httpResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[httpResponse.ResponseInfoCount].Length = -#if ASPNET50 - (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); -#else +#if ASPNETCORE50 (uint)Marshal.SizeOf(); +#else + (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); #endif UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); @@ -911,10 +911,10 @@ namespace Microsoft.Net.Http.Server private static int GetTokenOffsetFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); -#if ASPNET50 - IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelToken")); -#else +#if ASPNETCORE50 IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); +#else + IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelToken")); #endif Debug.Assert(tokenPointer != IntPtr.Zero); return (int)IntPtrHelper.Subtract(tokenPointer, blob); @@ -923,10 +923,10 @@ namespace Microsoft.Net.Http.Server private static int GetTokenSizeFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); -#if ASPNET50 - return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelTokenSize")); -#else +#if ASPNETCORE50 return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); +#else + return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelTokenSize")); #endif } diff --git a/src/Microsoft.Net.Http.Server/WebListenerException.cs b/src/Microsoft.Net.Http.Server/WebListenerException.cs index e411eccbff..0b31af9e66 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerException.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerException.cs @@ -45,12 +45,12 @@ namespace Microsoft.Net.Http.Server : base(errorCode, message) { } -#if ASPNET50 +#if ASPNETCORE50 + public int ErrorCode +#else // the base class returns the HResult with this property // we need the Win32 Error Code, hence the override. public override int ErrorCode -#else - public int ErrorCode #endif { get diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs index c32fe193c6..cdfef44a33 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if !ASPNET50 +#if ASPNETCORE50 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 93ae53059d..5e1b351113 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if !ASPNET50 +#if ASPNETCORE50 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs index 27c11162bb..b58cb2b3b6 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !ASPNET50 +#if ASPNETCORE50 using System; using System.ComponentModel; diff --git a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs index 50235a6447..d0c06faf22 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs @@ -21,17 +21,13 @@ // //------------------------------------------------------------------------------ -#if !ASPNET50 +#if ASPNETCORE50 namespace System { internal static class ExternDll { -#if ASPNETCORE50 public const string api_ms_win_core_localization_LIB = "api-ms-win-core-localization-l2-1-0.dll"; -#else - public const string Kernel32 = "kernel32.dll"; -#endif } } #endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs index 7ddb66a918..ff4cc36e0e 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if !ASPNET50 +#if ASPNETCORE50 namespace System.Runtime.InteropServices { diff --git a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs index da9548c88b..4fdd2d425d 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !ASPNET50 +#if ASPNETCORE50 using System.Runtime.InteropServices; using System.Text; @@ -36,11 +36,7 @@ namespace System FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; -#if ASPNETCORE50 [DllImport(ExternDll.api_ms_win_core_localization_LIB, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] -#else - [DllImport(ExternDll.Kernel32, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] -#endif public static unsafe extern int FormatMessage(int dwFlags, IntPtr lpSource_mustBeNull, uint dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr[] arguments); } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index f9abeb9eea..1cede4c5cd 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -8,7 +8,8 @@ "allowUnsafe": true }, "frameworks": { - "aspnet50": {}, + "net45": { }, + "aspnet50": { }, "aspnetcore50": { "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs index 02de75baaa..57fa75659a 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs @@ -87,7 +87,7 @@ namespace Microsoft.Net.WebSockets get { return Environment.HasShutdownStarted -#if ASPNET50 +#if !ASPNETCORE50 || AppDomain.CurrentDomain.IsFinalizingForUnload() #endif ; diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs index 52de2495d6..b365a0a701 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -173,10 +173,10 @@ namespace Microsoft.Net.WebSockets static WebSocketProtocolComponent() { -#if ASPNET50 - DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); -#else +#if ASPNETCORE50 DllFileName = Path.Combine(Environment.GetEnvironmentVariable("SYSTEMROOT"), "System32", WEBSOCKET); +#else + DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); #endif WebSocketDllHandle = SafeLoadLibrary.LoadLibraryEx(DllFileName); diff --git a/src/Microsoft.Net.WebSockets/WebSocketBase.cs b/src/Microsoft.Net.WebSockets/WebSocketBase.cs index d845cc1625..4254062785 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBase.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBase.cs @@ -1103,7 +1103,7 @@ namespace Microsoft.Net.WebSockets if (thisLockTaken || sessionHandleLockTaken) { -#if ASPNET50 +#if !ASPNETCORE50 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -1189,7 +1189,7 @@ namespace Microsoft.Net.WebSockets Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); if (lockTaken) { -#if ASPNET50 +#if !ASPNETCORE50 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -2253,7 +2253,9 @@ namespace Microsoft.Net.WebSockets "'webSocket.m_KeepAliveTracker' MUST NOT be NULL at this point."); int keepAliveIntervalMilliseconds = (int)_keepAliveInterval.TotalMilliseconds; Contract.Assert(keepAliveIntervalMilliseconds > 0, "'keepAliveIntervalMilliseconds' MUST be POSITIVE."); -#if ASPNET50 +#if ASPNETCORE50 + _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); +#else if (ExecutionContext.IsFlowSuppressed()) { _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); @@ -2265,8 +2267,6 @@ namespace Microsoft.Net.WebSockets _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); } } -#else - _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); #endif } diff --git a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs index 7378812572..62323a106f 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs @@ -50,12 +50,12 @@ namespace Microsoft.Net.WebSockets public const int MinSendBufferSize = 16; internal const int MinReceiveBufferSize = 256; internal const int MaxBufferSize = 64 * 1024; -#if ASPNET50 - private static readonly int SizeOfUInt = Marshal.SizeOf(typeof(uint)); - private static readonly int SizeOfBool = Marshal.SizeOf(typeof(bool)); -#else +#if ASPNETCORE50 private static readonly int SizeOfUInt = Marshal.SizeOf(); private static readonly int SizeOfBool = Marshal.SizeOf(); +#else + private static readonly int SizeOfUInt = Marshal.SizeOf(typeof(uint)); + private static readonly int SizeOfBool = Marshal.SizeOf(typeof(bool)); #endif private static readonly int PropertyBufferSize = (2 * SizeOfUInt) + SizeOfBool + IntPtr.Size; diff --git a/src/Microsoft.Net.WebSockets/WebSocketException.cs b/src/Microsoft.Net.WebSockets/WebSocketException.cs index 74ee1663e8..6dd5d72c73 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketException.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketException.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; namespace Microsoft.Net.WebSockets { -#if ASPNET50 +#if !ASPNETCORE50 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] #endif internal sealed class WebSocketException : Win32Exception diff --git a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 93ae53059d..5e1b351113 100644 --- a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if !ASPNET50 +#if ASPNETCORE50 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs index 7c0f5bf195..97e4ee049a 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if !ASPNET50 +#if ASPNETCORE50 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs index bdd0fa07bd..73f28a2b6e 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !ASPNET50 +#if ASPNETCORE50 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs index c1e1f5b20f..d0c06faf22 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs @@ -21,17 +21,13 @@ // //------------------------------------------------------------------------------ -#if !ASPNET50 +#if ASPNETCORE50 namespace System { internal static class ExternDll { -#if NETFX || ASPNET50 - public const string Kernel32 = "kernel32.dll"; -#else public const string api_ms_win_core_localization_LIB = "api-ms-win-core-localization-l2-1-0.dll"; -#endif } } #endif \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs index 7ddb66a918..ff4cc36e0e 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if !ASPNET50 +#if ASPNETCORE50 namespace System.Runtime.InteropServices { diff --git a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs index 7ee12dbbdc..4fdd2d425d 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if !ASPNET50 +#if ASPNETCORE50 using System.Runtime.InteropServices; using System.Text; @@ -36,11 +36,7 @@ namespace System FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; -#if ASPNETCORE50 [DllImport(ExternDll.api_ms_win_core_localization_LIB, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] -#else - [DllImport(ExternDll.Kernel32, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] -#endif public static unsafe extern int FormatMessage(int dwFlags, IntPtr lpSource_mustBeNull, uint dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr[] arguments); } diff --git a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs index 3ab212bca4..5bcc7aeaa0 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if !ASPNET50 +#if ASPNETCORE50 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 8a03bfb293..c997ebc250 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -5,7 +5,7 @@ }, "compilationOptions" : { "allowUnsafe": true }, "frameworks": { - "aspnet50" : { }, + "net45" : { }, "aspnetcore50" : { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index f630a6a85f..21aa1eb02f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal("Hello World", response); } } -#if ASPNET50 +#if !ASPNETCORE50 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 0c0784e8e7..37f11f8ff3 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,18 +1,18 @@ { - "commands": { - "test": "Xunit.KRunner" - }, - "dependencies": { - "Microsoft.Net.Http.Server" : "", - "Xunit.KRunner": "1.0.0-*" - }, - "frameworks": { - "aspnet50": { - "dependencies": { - "System.Net.Http": "", - "System.Net.Http.WebRequest": "", - "System.Runtime": "" + "commands": { + "test": "Xunit.KRunner" + }, + "dependencies": { + "System.Net.Http": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "Microsoft.Net.Http.Server": "1.0.0-*", + "Xunit.KRunner": "1.0.0-*" + }, + "frameworks": { + "net45": { + dependencies: { + "System.Net.Http.WebRequest": "" } } - } + } } From 31b4a9598d72fc56a2ec135ae9aa9c7066e64791 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 5 Oct 2014 14:14:03 -0700 Subject: [PATCH 124/597] Fixup references --- samples/HelloWorld/project.json | 28 +++--- samples/SelfHostServer/project.json | 34 ++----- .../project.json | 88 +++++++++---------- src/Microsoft.Net.Http.Server/project.json | 84 +++++++++--------- src/Microsoft.Net.WebSockets/project.json | 74 ++++++++-------- .../project.json | 41 +++++---- .../project.json | 9 +- 7 files changed, 168 insertions(+), 190 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 4f4c0e622f..063d259840 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,18 +1,18 @@ { - "dependencies": { - "Microsoft.Net.Http.Server" : "" - }, - "frameworks": { - "aspnet50": { }, - "aspnetcore50" : { - "dependencies": { - "System.Collections": "4.0.10.0", - "System.Console" : "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO" : "4.0.0.0", - "System.Runtime" : "4.0.20.0", - "System.Threading.Tasks": "4.0.10.0" + "dependencies": { + "Microsoft.Net.Http.Server": "1.0.0-*" + }, + "frameworks": { + "aspnet50": { }, + "aspnetcore50": { + "dependencies": { + "System.Collections": "4.0.10.0", + "System.Console": "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "System.Threading.Tasks": "4.0.10.0" + } } } - } } diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 4ae5346393..cbb2e6e7f1 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,31 +1,11 @@ { - "dependencies": { - "Microsoft.AspNet.Hosting": "1.0.0-*", - "Microsoft.AspNet.Http": "1.0.0-*", - "Microsoft.AspNet.Server.WebListener": "", - "Microsoft.Net.Http.Server": "" - }, - "commands": { "web": "Microsoft.AspNet.Hosting --server=Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:8080" }, - "frameworks": { - "aspnet50": { + "dependencies": { + "Microsoft.AspNet.Http": "1.0.0-*", + "Microsoft.AspNet.Server.WebListener": "1.0.0-*" }, - "aspnetcore50": { - "dependencies": { - "System.Collections": "4.0.10.0", - "System.Console": "4.0.0.0", - "System.Diagnostics.Debug": "4.0.10.0", - "System.Diagnostics.Tools": "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO": "4.0.10.0", - "System.IO.FileSystem": "4.0.0.0", - "System.Linq": "4.0.0.0", - "System.Reflection": "4.0.10.0", - "System.Resources.ResourceManager": "4.0.0.0", - "System.Runtime": "4.0.20.0", - "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.InteropServices": "4.0.20.0", - "System.Threading.Tasks": "4.0.10.0" - } + "commands": { "web": "Microsoft.AspNet.Hosting --server=Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:8080" }, + "frameworks": { + "aspnet50": { }, + "aspnetcore50": { } } - } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 591611cf37..52f87abd62 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,47 +1,47 @@ { - "version": "1.0.0-*", - "dependencies": { - "Microsoft.AspNet.FeatureModel": "1.0.0-*", - "Microsoft.AspNet.Http": "1.0.0-*", - "Microsoft.AspNet.HttpFeature": "1.0.0-*", - "Microsoft.Framework.ConfigurationModel": "1.0.0-*", - "Microsoft.Framework.Logging": "1.0.0-*", - "Microsoft.Net.Http.Server" : "", - "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" - }, - "compilationOptions": { - "allowUnsafe": true - }, - "frameworks": { - "aspnet50": {}, - "aspnetcore50": { - "dependencies": { - "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.10.0", - "System.Collections.Concurrent": "4.0.0.0", - "System.Diagnostics.Contracts": "4.0.0.0", - "System.Diagnostics.Debug": "4.0.10.0", - "System.Diagnostics.Tools": "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO": "4.0.10.0", - "System.Linq": "4.0.0.0", - "System.Net.Primitives": "4.0.10.0", - "System.Reflection": "4.0.10.0", - "System.Resources.ResourceManager": "4.0.0.0", - "System.Runtime": "4.0.20.0", - "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.Handles": "4.0.0.0", - "System.Runtime.InteropServices": "4.0.20.0", - "System.Security.Claims": "1.0.0-*", - "System.Security.Cryptography.X509Certificates": "4.0.0.0", - "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.10.0", - "System.Text.Encoding.Extensions": "4.0.10.0", - "System.Threading": "4.0.0.0", - "System.Threading.Overlapped": "4.0.0.0", - "System.Threading.Tasks": "4.0.10.0", - "System.Threading.ThreadPool": "4.0.10.0" - } + "version": "1.0.0-*", + "dependencies": { + "Microsoft.AspNet.FeatureModel": "1.0.0-*", + "Microsoft.AspNet.Http": "1.0.0-*", + "Microsoft.AspNet.HttpFeature": { "version": "1.0.0-*", "type": "build" }, + "Microsoft.Framework.ConfigurationModel": "1.0.0-*", + "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Net.Http.Server": "1.0.0-*", + "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" + }, + "compilationOptions": { + "allowUnsafe": true + }, + "frameworks": { + "aspnet50": { }, + "aspnetcore50": { + "dependencies": { + "Microsoft.Win32.Primitives": "4.0.0.0", + "System.Collections": "4.0.10.0", + "System.Collections.Concurrent": "4.0.0.0", + "System.Diagnostics.Contracts": "4.0.0.0", + "System.Diagnostics.Debug": "4.0.10.0", + "System.Diagnostics.Tools": "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO": "4.0.10.0", + "System.Linq": "4.0.0.0", + "System.Net.Primitives": "4.0.10.0", + "System.Reflection": "4.0.10.0", + "System.Resources.ResourceManager": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "System.Runtime.Extensions": "4.0.10.0", + "System.Runtime.Handles": "4.0.0.0", + "System.Runtime.InteropServices": "4.0.20.0", + "System.Security.Claims": "1.0.0-*", + "System.Security.Cryptography.X509Certificates": "4.0.0.0", + "System.Security.Principal": "4.0.0.0", + "System.Text.Encoding": "4.0.10.0", + "System.Text.Encoding.Extensions": "4.0.10.0", + "System.Threading": "4.0.0.0", + "System.Threading.Overlapped": "4.0.0.0", + "System.Threading.Tasks": "4.0.10.0", + "System.Threading.ThreadPool": "4.0.10.0" + } + } } - } } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 1cede4c5cd..0788160c08 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,45 +1,45 @@ { - "version": "1.0.0-*", - "dependencies": { - "Microsoft.Framework.Logging": "1.0.0-*", - "Microsoft.Net.WebSockets": "" - }, - "compilationOptions": { - "allowUnsafe": true - }, - "frameworks": { - "net45": { }, - "aspnet50": { }, - "aspnetcore50": { - "dependencies": { - "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", - "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.10.0", - "System.Collections.Concurrent": "4.0.0.0", - "System.Diagnostics.Contracts": "4.0.0.0", - "System.Diagnostics.Debug": "4.0.10.0", - "System.Diagnostics.Tools": "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO": "4.0.10.0", - "System.IO.FileSystem": "4.0.0.0", - "System.Linq": "4.0.0.0", - "System.Net.Primitives": "4.0.10.0", - "System.Reflection": "4.0.10.0", - "System.Resources.ResourceManager": "4.0.0.0", - "System.Runtime": "4.0.20.0", - "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.Handles": "4.0.0.0", - "System.Runtime.InteropServices": "4.0.20.0", - "System.Security.Claims": "1.0.0-*", - "System.Security.Cryptography.X509Certificates": "4.0.0.0", - "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.10.0", - "System.Text.Encoding.Extensions": "4.0.10.0", - "System.Threading": "4.0.0.0", - "System.Threading.Overlapped": "4.0.0.0", - "System.Threading.Tasks": "4.0.10.0", - "System.Threading.ThreadPool": "4.0.10.0" - } + "version": "1.0.0-*", + "dependencies": { + "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Net.WebSockets": "1.0.0-*" + }, + "compilationOptions": { + "allowUnsafe": true + }, + "frameworks": { + "net45": { }, + "aspnet50": { }, + "aspnetcore50": { + "dependencies": { + "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", + "Microsoft.Win32.Primitives": "4.0.0.0", + "System.Collections": "4.0.10.0", + "System.Collections.Concurrent": "4.0.0.0", + "System.Diagnostics.Contracts": "4.0.0.0", + "System.Diagnostics.Debug": "4.0.10.0", + "System.Diagnostics.Tools": "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO": "4.0.10.0", + "System.IO.FileSystem": "4.0.0.0", + "System.Linq": "4.0.0.0", + "System.Net.Primitives": "4.0.10.0", + "System.Reflection": "4.0.10.0", + "System.Resources.ResourceManager": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "System.Runtime.Extensions": "4.0.10.0", + "System.Runtime.Handles": "4.0.0.0", + "System.Runtime.InteropServices": "4.0.20.0", + "System.Security.Claims": "1.0.0-*", + "System.Security.Cryptography.X509Certificates": "4.0.0.0", + "System.Security.Principal": "4.0.0.0", + "System.Text.Encoding": "4.0.10.0", + "System.Text.Encoding.Extensions": "4.0.10.0", + "System.Threading": "4.0.0.0", + "System.Threading.Overlapped": "4.0.0.0", + "System.Threading.Tasks": "4.0.10.0", + "System.Threading.ThreadPool": "4.0.10.0" + } + } } - } } diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index c997ebc250..289e8628ab 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,40 +1,40 @@ { - "version": "1.0.0-*", - "dependencies": { + "version": "1.0.0-*", + "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" - }, - "compilationOptions" : { "allowUnsafe": true }, - "frameworks": { - "net45" : { }, - "aspnetcore50" : { - "dependencies": { - "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.10.0", - "System.Collections.Concurrent": "4.0.0.0", - "System.Diagnostics.Contracts": "4.0.0.0", - "System.Diagnostics.Debug": "4.0.10.0", - "System.Diagnostics.Tools": "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO": "4.0.10.0", - "System.Linq": "4.0.0.0", - "System.Net.Primitives": "4.0.10.0", - "System.Reflection": "4.0.10.0", - "System.Resources.ResourceManager": "4.0.0.0", - "System.Runtime": "4.0.20.0", - "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.Handles": "4.0.0.0", - "System.Runtime.InteropServices": "4.0.20.0", - "System.Security.Cryptography.Encryption": "4.0.0.0", - "System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0", - "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.10.0", - "System.Text.Encoding.Extensions": "4.0.10.0", - "System.Threading": "4.0.0.0", - "System.Threading.Overlapped": "4.0.0.0", - "System.Threading.Tasks": "4.0.10.0", - "System.Threading.Timer": "4.0.0.0", - "System.Threading.ThreadPool": "4.0.10.0" - } - } - } + }, + "compilationOptions": { "allowUnsafe": true }, + "frameworks": { + "net45": { }, + "aspnetcore50": { + "dependencies": { + "Microsoft.Win32.Primitives": "4.0.0.0", + "System.Collections": "4.0.10.0", + "System.Collections.Concurrent": "4.0.0.0", + "System.Diagnostics.Contracts": "4.0.0.0", + "System.Diagnostics.Debug": "4.0.10.0", + "System.Diagnostics.Tools": "4.0.0.0", + "System.Globalization": "4.0.10.0", + "System.IO": "4.0.10.0", + "System.Linq": "4.0.0.0", + "System.Net.Primitives": "4.0.10.0", + "System.Reflection": "4.0.10.0", + "System.Resources.ResourceManager": "4.0.0.0", + "System.Runtime": "4.0.20.0", + "System.Runtime.Extensions": "4.0.10.0", + "System.Runtime.Handles": "4.0.0.0", + "System.Runtime.InteropServices": "4.0.20.0", + "System.Security.Cryptography.Encryption": "4.0.0.0", + "System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0", + "System.Security.Principal": "4.0.0.0", + "System.Text.Encoding": "4.0.10.0", + "System.Text.Encoding.Extensions": "4.0.10.0", + "System.Threading": "4.0.0.0", + "System.Threading.Overlapped": "4.0.0.0", + "System.Threading.Tasks": "4.0.10.0", + "System.Threading.Timer": "4.0.0.0", + "System.Threading.ThreadPool": "4.0.10.0" + } + } + } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index edff879192..612efee8b1 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,26 +1,25 @@ { - "commands": { - "test": "Xunit.KRunner" - }, - "dependencies": { - "Microsoft.AspNet.FeatureModel" : "1.0.0-*", - "Microsoft.AspNet.Hosting": "1.0.0-*", - "Microsoft.AspNet.Http" : "1.0.0-*", - "Microsoft.AspNet.HttpFeature" : "1.0.0-*", - "Microsoft.AspNet.PipelineCore" : "1.0.0-*", - "Microsoft.AspNet.Server.WebListener" : "", - "Microsoft.Framework.ConfigurationModel": "1.0.0-*", - "Microsoft.Framework.Logging": "1.0.0-*", - "Microsoft.Net.Http.Server" : "", - "Xunit.KRunner": "1.0.0-*" - }, - "frameworks": { + "commands": { + "test": "Xunit.KRunner" + }, + "dependencies": { + "Microsoft.AspNet.FeatureModel": "1.0.0-*", + "Microsoft.AspNet.Hosting": "1.0.0-*", + "Microsoft.AspNet.Http": "1.0.0-*", + "Microsoft.AspNet.HttpFeature": "1.0.0-*", + "Microsoft.AspNet.PipelineCore": "1.0.0-*", + "Microsoft.AspNet.Server.WebListener": "", + "Microsoft.Framework.ConfigurationModel": "1.0.0-*", + "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Net.Http.Server": "1.0.0-*", + "Xunit.KRunner": "1.0.0-*" + }, + "frameworks": { "aspnet50": { - "dependencies": { - "System.Net.Http": "", - "System.Net.Http.WebRequest": "", - "System.Runtime": "" + "frameworkAssemblies": { + "System.Net.Http": "4.0.0.0", + "System.Net.Http.WebRequest": "4.0.0.0" } } - } + } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 37f11f8ff3..91d2dad8aa 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -3,15 +3,14 @@ "test": "Xunit.KRunner" }, "dependencies": { - "System.Net.Http": "4.0.0.0", - "System.Runtime": "4.0.20.0", "Microsoft.Net.Http.Server": "1.0.0-*", "Xunit.KRunner": "1.0.0-*" }, "frameworks": { - "net45": { - dependencies: { - "System.Net.Http.WebRequest": "" + "aspnet50": { + frameworkAssemblies: { + "System.Net.Http": "4.0.0.0", + "System.Net.Http.WebRequest": "4.0.0.0" } } } From 8b774e3abfb1d139b30d61fa1d000645e05620d8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 10 Oct 2014 10:34:50 -0700 Subject: [PATCH 125/597] Reacting to CLR package versioning changes --- samples/HelloWorld/project.json | 12 ++--- .../project.json | 46 ++++++++--------- src/Microsoft.Net.Http.Server/project.json | 48 +++++++++--------- src/Microsoft.Net.WebSockets/project.json | 50 +++++++++---------- .../project.json | 4 +- .../project.json | 4 +- 6 files changed, 82 insertions(+), 82 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 063d259840..6f76aa53bc 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -6,12 +6,12 @@ "aspnet50": { }, "aspnetcore50": { "dependencies": { - "System.Collections": "4.0.10.0", - "System.Console": "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO": "4.0.0.0", - "System.Runtime": "4.0.20.0", - "System.Threading.Tasks": "4.0.10.0" + "System.Collections": "4.0.10-beta-*", + "System.Console": "4.0.0-beta-*", + "System.Globalization": "4.0.10-beta-*", + "System.IO": "4.0.0-beta-*", + "System.Runtime": "4.0.20-beta-*", + "System.Threading.Tasks": "4.0.10-beta-*" } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 52f87abd62..20b22d72eb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -17,30 +17,30 @@ "aspnetcore50": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.10.0", - "System.Collections.Concurrent": "4.0.0.0", - "System.Diagnostics.Contracts": "4.0.0.0", - "System.Diagnostics.Debug": "4.0.10.0", - "System.Diagnostics.Tools": "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO": "4.0.10.0", - "System.Linq": "4.0.0.0", - "System.Net.Primitives": "4.0.10.0", - "System.Reflection": "4.0.10.0", - "System.Resources.ResourceManager": "4.0.0.0", - "System.Runtime": "4.0.20.0", - "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.Handles": "4.0.0.0", - "System.Runtime.InteropServices": "4.0.20.0", + "System.Collections": "4.0.10-beta-*", + "System.Collections.Concurrent": "4.0.0-beta-*", + "System.Diagnostics.Contracts": "4.0.0-beta-*", + "System.Diagnostics.Debug": "4.0.10-beta-*", + "System.Diagnostics.Tools": "4.0.0-beta-*", + "System.Globalization": "4.0.10-beta-*", + "System.IO": "4.0.10-beta-*", + "System.Linq": "4.0.0-beta-*", + "System.Net.Primitives": "4.0.10-beta-*", + "System.Reflection": "4.0.10-beta-*", + "System.Resources.ResourceManager": "4.0.0-beta-*", + "System.Runtime": "4.0.20-beta-*", + "System.Runtime.Extensions": "4.0.10-beta-*", + "System.Runtime.Handles": "4.0.0-beta-*", + "System.Runtime.InteropServices": "4.0.20-beta-*", "System.Security.Claims": "1.0.0-*", - "System.Security.Cryptography.X509Certificates": "4.0.0.0", - "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.10.0", - "System.Text.Encoding.Extensions": "4.0.10.0", - "System.Threading": "4.0.0.0", - "System.Threading.Overlapped": "4.0.0.0", - "System.Threading.Tasks": "4.0.10.0", - "System.Threading.ThreadPool": "4.0.10.0" + "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", + "System.Security.Principal": "4.0.0-beta-*", + "System.Text.Encoding": "4.0.10-beta-*", + "System.Text.Encoding.Extensions": "4.0.10-beta-*", + "System.Threading": "4.0.0-beta-*", + "System.Threading.Overlapped": "4.0.0-beta-*", + "System.Threading.Tasks": "4.0.10-beta-*", + "System.Threading.ThreadPool": "4.0.10-beta-*" } } } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 0788160c08..acdb4219bb 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -14,31 +14,31 @@ "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.10.0", - "System.Collections.Concurrent": "4.0.0.0", - "System.Diagnostics.Contracts": "4.0.0.0", - "System.Diagnostics.Debug": "4.0.10.0", - "System.Diagnostics.Tools": "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO": "4.0.10.0", - "System.IO.FileSystem": "4.0.0.0", - "System.Linq": "4.0.0.0", - "System.Net.Primitives": "4.0.10.0", - "System.Reflection": "4.0.10.0", - "System.Resources.ResourceManager": "4.0.0.0", - "System.Runtime": "4.0.20.0", - "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.Handles": "4.0.0.0", - "System.Runtime.InteropServices": "4.0.20.0", + "System.Collections": "4.0.10-beta-*", + "System.Collections.Concurrent": "4.0.0-beta-*", + "System.Diagnostics.Contracts": "4.0.0-beta-*", + "System.Diagnostics.Debug": "4.0.10-beta-*", + "System.Diagnostics.Tools": "4.0.0-beta-*", + "System.Globalization": "4.0.10-beta-*", + "System.IO": "4.0.10-beta-*", + "System.IO.FileSystem": "4.0.0-beta-*", + "System.Linq": "4.0.0-beta-*", + "System.Net.Primitives": "4.0.10-beta-*", + "System.Reflection": "4.0.10-beta-*", + "System.Resources.ResourceManager": "4.0.0-beta-*", + "System.Runtime": "4.0.20-beta-*", + "System.Runtime.Extensions": "4.0.10-beta-*", + "System.Runtime.Handles": "4.0.0-beta-*", + "System.Runtime.InteropServices": "4.0.20-beta-*", "System.Security.Claims": "1.0.0-*", - "System.Security.Cryptography.X509Certificates": "4.0.0.0", - "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.10.0", - "System.Text.Encoding.Extensions": "4.0.10.0", - "System.Threading": "4.0.0.0", - "System.Threading.Overlapped": "4.0.0.0", - "System.Threading.Tasks": "4.0.10.0", - "System.Threading.ThreadPool": "4.0.10.0" + "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", + "System.Security.Principal": "4.0.0-beta-*", + "System.Text.Encoding": "4.0.10-beta-*", + "System.Text.Encoding.Extensions": "4.0.10-beta-*", + "System.Threading": "4.0.0-beta-*", + "System.Threading.Overlapped": "4.0.0-beta-*", + "System.Threading.Tasks": "4.0.10-beta-*", + "System.Threading.ThreadPool": "4.0.10-beta-*" } } } diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 289e8628ab..b4cfc74b59 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -9,31 +9,31 @@ "aspnetcore50": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0.0", - "System.Collections": "4.0.10.0", - "System.Collections.Concurrent": "4.0.0.0", - "System.Diagnostics.Contracts": "4.0.0.0", - "System.Diagnostics.Debug": "4.0.10.0", - "System.Diagnostics.Tools": "4.0.0.0", - "System.Globalization": "4.0.10.0", - "System.IO": "4.0.10.0", - "System.Linq": "4.0.0.0", - "System.Net.Primitives": "4.0.10.0", - "System.Reflection": "4.0.10.0", - "System.Resources.ResourceManager": "4.0.0.0", - "System.Runtime": "4.0.20.0", - "System.Runtime.Extensions": "4.0.10.0", - "System.Runtime.Handles": "4.0.0.0", - "System.Runtime.InteropServices": "4.0.20.0", - "System.Security.Cryptography.Encryption": "4.0.0.0", - "System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0", - "System.Security.Principal": "4.0.0.0", - "System.Text.Encoding": "4.0.10.0", - "System.Text.Encoding.Extensions": "4.0.10.0", - "System.Threading": "4.0.0.0", - "System.Threading.Overlapped": "4.0.0.0", - "System.Threading.Tasks": "4.0.10.0", - "System.Threading.Timer": "4.0.0.0", - "System.Threading.ThreadPool": "4.0.10.0" + "System.Collections": "4.0.10-beta-*", + "System.Collections.Concurrent": "4.0.0-beta-*", + "System.Diagnostics.Contracts": "4.0.0-beta-*", + "System.Diagnostics.Debug": "4.0.10-beta-*", + "System.Diagnostics.Tools": "4.0.0-beta-*", + "System.Globalization": "4.0.10-beta-*", + "System.IO": "4.0.10-beta-*", + "System.Linq": "4.0.0-beta-*", + "System.Net.Primitives": "4.0.10-beta-*", + "System.Reflection": "4.0.10-beta-*", + "System.Resources.ResourceManager": "4.0.0-beta-*", + "System.Runtime": "4.0.20-beta-*", + "System.Runtime.Extensions": "4.0.10-beta-*", + "System.Runtime.Handles": "4.0.0-beta-*", + "System.Runtime.InteropServices": "4.0.20-beta-*", + "System.Security.Cryptography.Encryption": "4.0.0-beta-*", + "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", + "System.Security.Principal": "4.0.0-beta-*", + "System.Text.Encoding": "4.0.10-beta-*", + "System.Text.Encoding.Extensions": "4.0.10-beta-*", + "System.Threading": "4.0.0-beta-*", + "System.Threading.Overlapped": "4.0.0-beta-*", + "System.Threading.Tasks": "4.0.10-beta-*", + "System.Threading.Timer": "4.0.0-beta-*", + "System.Threading.ThreadPool": "4.0.10-beta-*" } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 612efee8b1..4784fa8707 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -17,8 +17,8 @@ "frameworks": { "aspnet50": { "frameworkAssemblies": { - "System.Net.Http": "4.0.0.0", - "System.Net.Http.WebRequest": "4.0.0.0" + "System.Net.Http": "4.0.0-beta-*", + "System.Net.Http.WebRequest": "4.0.0-beta-*" } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 91d2dad8aa..7c019fc0b8 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -9,8 +9,8 @@ "frameworks": { "aspnet50": { frameworkAssemblies: { - "System.Net.Http": "4.0.0.0", - "System.Net.Http.WebRequest": "4.0.0.0" + "System.Net.Http": "4.0.0-beta-*", + "System.Net.Http.WebRequest": "4.0.0-beta-*" } } } From c6d2d2ce243ffcab09c4dc24616f88a97b107b32 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 10 Oct 2014 10:55:55 -0700 Subject: [PATCH 126/597] Removing version from framework assemblies node --- .../project.json | 4 ++-- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 4784fa8707..a8ab3c7d16 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -17,8 +17,8 @@ "frameworks": { "aspnet50": { "frameworkAssemblies": { - "System.Net.Http": "4.0.0-beta-*", - "System.Net.Http.WebRequest": "4.0.0-beta-*" + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 7c019fc0b8..9349360b84 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -9,8 +9,8 @@ "frameworks": { "aspnet50": { frameworkAssemblies: { - "System.Net.Http": "4.0.0-beta-*", - "System.Net.Http.WebRequest": "4.0.0-beta-*" + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" } } } From b43c27763dcf2d7135bd4d530301eb58d726fced Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 10 Oct 2014 15:15:57 -0700 Subject: [PATCH 127/597] Reacting to CoreCLR version changes --- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- src/Microsoft.Net.WebSockets/project.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 20b22d72eb..59de096b54 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -16,7 +16,7 @@ "aspnet50": { }, "aspnetcore50": { "dependencies": { - "Microsoft.Win32.Primitives": "4.0.0.0", + "Microsoft.Win32.Primitives": "4.0.0-beta-*", "System.Collections": "4.0.10-beta-*", "System.Collections.Concurrent": "4.0.0-beta-*", "System.Diagnostics.Contracts": "4.0.0-beta-*", diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index acdb4219bb..6be4acb186 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -13,7 +13,7 @@ "aspnetcore50": { "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", - "Microsoft.Win32.Primitives": "4.0.0.0", + "Microsoft.Win32.Primitives": "4.0.0-beta-*", "System.Collections": "4.0.10-beta-*", "System.Collections.Concurrent": "4.0.0-beta-*", "System.Diagnostics.Contracts": "4.0.0-beta-*", diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index b4cfc74b59..6280518ea0 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -8,7 +8,7 @@ "net45": { }, "aspnetcore50": { "dependencies": { - "Microsoft.Win32.Primitives": "4.0.0.0", + "Microsoft.Win32.Primitives": "4.0.0-beta-*", "System.Collections": "4.0.10-beta-*", "System.Collections.Concurrent": "4.0.0-beta-*", "System.Diagnostics.Contracts": "4.0.0-beta-*", From 93a88af4671ae68d11aa162181d4c6ca77045a36 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 9 Oct 2014 17:00:34 -0700 Subject: [PATCH 128/597] Purge old tests. --- .../DenyAnonymous.cs | 64 ---- .../DictionaryExtensions.cs | 68 ----- .../DigestTests.cs | 261 ---------------- .../NegotiateTests.cs | 278 ------------------ .../PassThroughTests.cs | 81 ----- .../Properties/AssemblyInfo.cs | 59 ---- .../project.json | 18 -- 7 files changed, 829 deletions(-) delete mode 100644 test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs delete mode 100644 test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs delete mode 100644 test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs delete mode 100644 test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs delete mode 100644 test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs delete mode 100644 test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs delete mode 100644 test/Microsoft.AspNet.Security.Windows.Test/project.json diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs b/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs deleted file mode 100644 index 19a04912dd..0000000000 --- a/test/Microsoft.AspNet.Security.Windows.Test/DenyAnonymous.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// -// Copyright 2011-2012 Katana contributors -// -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using System; -using System.Collections.Generic; -using System.Security.Principal; -using System.Threading.Tasks; - -namespace Microsoft.AspNet.Security.Windows.Tests -{ - using AppFunc = Func, Task>; - - // This middleware can be placed at the end of a chain of pass-through auth schemes if at least one type of auth is required. - public class DenyAnonymous - { - private readonly AppFunc _nextApp; - - public DenyAnonymous(AppFunc nextApp) - { - _nextApp = nextApp; - } - - public async Task Invoke(IDictionary env) - { - if (env.Get("server.User") == null) - { - env["owin.ResponseStatusCode"] = 401; - return; - } - - await _nextApp(env); - } - } -} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs b/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs deleted file mode 100644 index 7aa0e65d2c..0000000000 --- a/test/Microsoft.AspNet.Security.Windows.Test/DictionaryExtensions.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Linq; -using System.Text; - -namespace System.Collections.Generic -{ - internal static class DictionaryExtensions - { - internal static void Append(this IDictionary dictionary, string key, string value) - { - string[] orriginalValues; - if (dictionary.TryGetValue(key, out orriginalValues)) - { - string[] newValues = new string[orriginalValues.Length + 1]; - orriginalValues.CopyTo(newValues, 0); - newValues[newValues.Length - 1] = value; - dictionary[key] = newValues; - } - else - { - dictionary[key] = new string[] { value }; - } - } - - internal static string Get(this IDictionary dictionary, string key) - { - string[] values; - if (dictionary.TryGetValue(key, out values)) - { - return string.Join(", ", values); - } - return null; - } - - internal static T Get(this IDictionary dictionary, string key, T fallback = default(T)) - { - object values; - if (dictionary.TryGetValue(key, out values)) - { - return (T)values; - } - return fallback; - } - } -} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs deleted file mode 100644 index 67d693ed66..0000000000 --- a/test/Microsoft.AspNet.Security.Windows.Test/DigestTests.cs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Security.Authentication.ExtendedProtection; -using System.Threading.Tasks; -using Microsoft.AspNet.Server.WebListener; -using Xunit; - -namespace Microsoft.AspNet.Security.Windows.Tests -{ - using AppFunc = Func, Task>; - - public class DigestTests - { - private const string Address = "http://localhost:8080/"; - private const string SecureAddress = "https://localhost:9090/"; - private const int DefaultStatusCode = 201; - - [Fact] - public async Task Digest_PartialMatch_PassedThrough() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); - IDictionary emptyEnv = CreateEmptyRequest("Authorization", "Digestion blablabla"); - await windowsAuth.Invoke(emptyEnv); - - Assert.Equal(DefaultStatusCode, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(0, responseHeaders.Count); - } - - [Fact] - public async Task Digest_BadData_400() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); - IDictionary emptyEnv = CreateEmptyRequest("Authorization", "Digest blablabla"); - await windowsAuth.Invoke(emptyEnv); - - Assert.Equal(400, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(0, responseHeaders.Count); - } - - [Fact] - public async Task Digest_AppSets401_401WithChallenge() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = AuthTypes.Digest; - IDictionary emptyEnv = CreateEmptyRequest(); - await windowsAuth.Invoke(emptyEnv); - FireOnSendingHeadersActions(emptyEnv); - - Assert.Equal(401, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(1, responseHeaders.Count); - Assert.NotNull(responseHeaders.Get("www-authenticate")); - Assert.True(responseHeaders.Get("www-authenticate").StartsWith("Digest ")); - } - - [Fact] - public async Task Digest_CbtOptionalButNotPresent_401WithChallenge() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = AuthTypes.Digest; - windowsAuth.ExtendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.WhenSupported); - IDictionary emptyEnv = CreateEmptyRequest(); - emptyEnv["owin.RequestScheme"] = "https"; - await windowsAuth.Invoke(emptyEnv); - FireOnSendingHeadersActions(emptyEnv); - - Assert.Equal(401, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(0, responseHeaders.Count); - Assert.Null(responseHeaders.Get("www-authenticate")); - } - - [Fact] - public async Task Digest_CbtRequiredButNotPresent_400() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = AuthTypes.Digest; - windowsAuth.ExtendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Always); - IDictionary emptyEnv = CreateEmptyRequest(); - emptyEnv["owin.RequestScheme"] = "https"; - await windowsAuth.Invoke(emptyEnv); - FireOnSendingHeadersActions(emptyEnv); - - Assert.Equal(401, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(0, responseHeaders.Count); - Assert.Null(responseHeaders.Get("www-authenticate")); - } - - [Fact(Skip = "Broken")] - public async Task Digest_ClientAuthenticates_Success() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = AuthTypes.Digest; - - using (CreateServer(windowsAuth.Invoke)) - { - HttpResponseMessage response = await SendAuthRequestAsync(Address); - Assert.Equal(DefaultStatusCode, (int)response.StatusCode); - } - } - - [Fact(Skip = "Broken")] - public async Task Digest_ClientAuthenticatesMultipleTimes_Success() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = AuthTypes.Digest; - - using (CreateServer(windowsAuth.Invoke)) - { - for (int i = 0; i < 10; i++) - { - HttpResponseMessage response = await SendAuthRequestAsync(Address); - Assert.Equal(DefaultStatusCode, (int)response.StatusCode); - } - } - } - - [Fact] - public async Task Digest_AnonmousClient_401() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = AuthTypes.Digest; - - using (CreateServer(windowsAuth.Invoke)) - { - HttpResponseMessage response = await SendRequestAsync(Address); - Assert.Equal(401, (int)response.StatusCode); - Assert.True(response.Headers.WwwAuthenticate.ToString().StartsWith("Digest ")); - } - } - - [Fact(Skip = "Broken")] - public async Task Digest_ClientAuthenticatesWithCbt_Success() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = AuthTypes.Digest; - windowsAuth.ExtendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Always); - - using (CreateSecureServer(windowsAuth.Invoke)) - { - HttpResponseMessage response = await SendAuthRequestAsync(SecureAddress); - Assert.Equal(DefaultStatusCode, (int)response.StatusCode); - } - } - - private IDictionary CreateEmptyRequest(string header = null, string value = null) - { - IDictionary env = new Dictionary(); - var requestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - env["owin.RequestHeaders"] = requestHeaders; - if (header != null) - { - requestHeaders[header] = new string[] { value }; - } - env["owin.ResponseHeaders"] = new Dictionary(StringComparer.OrdinalIgnoreCase); - - var onSendingHeadersActions = new List, object>>(); - env["server.OnSendingHeaders"] = new Action, object>( - (a, b) => onSendingHeadersActions.Add(new Tuple, object>(a, b))); - - env["test.OnSendingHeadersActions"] = onSendingHeadersActions; - return env; - } - - private void FireOnSendingHeadersActions(IDictionary env) - { - var onSendingHeadersActions = env.Get, object>>>("test.OnSendingHeadersActions"); - foreach (var actionPair in onSendingHeadersActions.Reverse()) - { - actionPair.Item1(actionPair.Item2); - } - } - - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - - private IDisposable CreateSecureServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "https"; - address["host"] = "localhost"; - address["port"] = "9090"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - - private async Task SendRequestAsync(string uri) - { - using (HttpClient client = new HttpClient()) - { - return await client.GetAsync(uri); - } - } - - private async Task SendAuthRequestAsync(string uri) - { - WebRequestHandler handler = new WebRequestHandler(); - handler.UseDefaultCredentials = true; - handler.ServerCertificateValidationCallback = (a, b, c, d) => true; - using (HttpClient client = new HttpClient(handler)) - { - return await client.GetAsync(uri); - } - } - - private Task SimpleApp(IDictionary env) - { - env["owin.ResponseStatusCode"] = DefaultStatusCode; - return Task.FromResult(null); - } - } -} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs deleted file mode 100644 index 6deff83ee1..0000000000 --- a/test/Microsoft.AspNet.Security.Windows.Test/NegotiateTests.cs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Security.Authentication.ExtendedProtection; -using System.Threading.Tasks; -using Microsoft.AspNet.Server.WebListener; -using Xunit; -using Xunit.Extensions; - -namespace Microsoft.AspNet.Security.Windows.Tests -{ - using AppFunc = Func, Task>; - - public class NegotiateTests - { - private const string Address = "http://localhost:8080/"; - private const string SecureAddress = "https://localhost:9090/"; - private const int DefaultStatusCode = 201; - - [Theory] - [InlineData("Negotiate")] - [InlineData("NTLM")] - public async Task Negotiate_PartialMatch_PassedThrough(string package) - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); - IDictionary emptyEnv = CreateEmptyRequest("Authorization", package + "ion blablabla"); - await windowsAuth.Invoke(emptyEnv); - - Assert.Equal(DefaultStatusCode, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(0, responseHeaders.Count); - } - - [Theory] - [InlineData("Negotiate")] - [InlineData("NTLM")] - public async Task Negotiate_BadData_400(string package) - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); - IDictionary emptyEnv = CreateEmptyRequest("Authorization", package + " blablabla"); - await windowsAuth.Invoke(emptyEnv); - - Assert.Equal(400, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(0, responseHeaders.Count); - } - - [Theory] - [InlineData("Negotiate")] - [InlineData("NTLM")] - public async Task Negotiate_AppSets401_401WithChallenge(string package) - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp401); - windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); - IDictionary emptyEnv = CreateEmptyRequest(); - await windowsAuth.Invoke(emptyEnv); - FireOnSendingHeadersActions(emptyEnv); - - Assert.Equal(401, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(1, responseHeaders.Count); - Assert.NotNull(responseHeaders.Get("www-authenticate")); - Assert.Equal(package, responseHeaders.Get("www-authenticate")); - } - - [Theory(Skip = "Broken")] - [InlineData("Negotiate")] - [InlineData("NTLM")] - public async Task Negotiate_ClientAuthenticates_Success(string package) - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); - - using (CreateServer(windowsAuth.Invoke)) - { - HttpResponseMessage response = await SendAuthRequestAsync(Address); - Assert.Equal(DefaultStatusCode, (int)response.StatusCode); - } - } - - [Theory(Skip = "Broken")] - [InlineData("Negotiate")] - [InlineData("NTLM")] - public async Task Negotiate_ClientAuthenticatesMultipleTimes_Success(string package) - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); - - using (CreateServer(windowsAuth.Invoke)) - { - for (int i = 0; i < 10; i++) - { - HttpResponseMessage response = await SendAuthRequestAsync(Address); - Assert.Equal(DefaultStatusCode, (int)response.StatusCode); - } - } - } - - [Theory] - [InlineData("Negotiate")] - [InlineData("NTLM")] - public async Task Negotiate_AnonmousClient_401(string package) - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); - - using (CreateServer(windowsAuth.Invoke)) - { - HttpResponseMessage response = await SendRequestAsync(Address); - Assert.Equal(401, (int)response.StatusCode); - Assert.Equal(package, response.Headers.WwwAuthenticate.ToString()); - } - } - - [Fact(Skip = "Broken")] - public async Task UnsafeSharedNTLM_AuthenticatedClient_Success() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = AuthTypes.Ntlm; - windowsAuth.UnsafeConnectionNtlmAuthentication = true; - - using (CreateServer(windowsAuth.Invoke)) - { - WebRequestHandler handler = new WebRequestHandler(); - CredentialCache cache = new CredentialCache(); - cache.Add(new Uri(Address), "NTLM", CredentialCache.DefaultNetworkCredentials); - handler.Credentials = cache; - handler.UnsafeAuthenticatedConnectionSharing = true; - using (HttpClient client = new HttpClient(handler)) - { - HttpResponseMessage response = await client.GetAsync(Address); - Assert.Equal(DefaultStatusCode, (int)response.StatusCode); - response.EnsureSuccessStatusCode(); - - // Remove the credentials before try two just to prove they aren't used. - cache.Remove(new Uri(Address), "NTLM"); - response = await client.GetAsync(Address); - Assert.Equal(DefaultStatusCode, (int)response.StatusCode); - } - } - } - - [Theory(Skip = "Broken")] - [InlineData("Negotiate")] - [InlineData("NTLM")] - public async Task Negotiate_ClientAuthenticatesWithCbt_Success(string package) - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(new DenyAnonymous(SimpleApp).Invoke); - windowsAuth.AuthenticationSchemes = (AuthTypes)Enum.Parse(typeof(AuthTypes), package, true); - windowsAuth.ExtendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Always); - - using (CreateSecureServer(windowsAuth.Invoke)) - { - HttpResponseMessage response = await SendAuthRequestAsync(SecureAddress); - Assert.Equal(DefaultStatusCode, (int)response.StatusCode); - } - } - - private IDictionary CreateEmptyRequest(string header = null, string value = null, string connectionId = "Random") - { - IDictionary env = new Dictionary(); - var requestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - env["owin.RequestHeaders"] = requestHeaders; - if (header != null) - { - requestHeaders[header] = new string[] { value }; - } - env["owin.ResponseHeaders"] = new Dictionary(StringComparer.OrdinalIgnoreCase); - - var onSendingHeadersActions = new List, object>>(); - env["server.OnSendingHeaders"] = new Action, object>( - (a, b) => onSendingHeadersActions.Add(new Tuple, object>(a, b))); - - env["test.OnSendingHeadersActions"] = onSendingHeadersActions; - env["server.ConnectionId"] = connectionId; - return env; - } - - private void FireOnSendingHeadersActions(IDictionary env) - { - var onSendingHeadersActions = env.Get, object>>>("test.OnSendingHeadersActions"); - foreach (var actionPair in onSendingHeadersActions.Reverse()) - { - actionPair.Item1(actionPair.Item2); - } - } - - private IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - - private IDisposable CreateSecureServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "https"; - address["host"] = "localhost"; - address["port"] = "9090"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - - private async Task SendRequestAsync(string uri) - { - using (HttpClient client = new HttpClient()) - { - return await client.GetAsync(uri); - } - } - - private async Task SendAuthRequestAsync(string uri) - { - WebRequestHandler handler = new WebRequestHandler(); - handler.UseDefaultCredentials = true; - handler.ServerCertificateValidationCallback = (a, b, c, d) => true; - using (HttpClient client = new HttpClient(handler)) - { - return await client.GetAsync(uri); - } - } - - private Task SimpleApp(IDictionary env) - { - env["owin.ResponseStatusCode"] = DefaultStatusCode; - return Task.FromResult(null); - } - - private Task SimpleApp401(IDictionary env) - { - env["owin.ResponseStatusCode"] = 401; - return Task.FromResult(null); - } - } -} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs b/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs deleted file mode 100644 index 03899b4593..0000000000 --- a/test/Microsoft.AspNet.Security.Windows.Test/PassThroughTests.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.AspNet.Security.Windows.Tests -{ - public class PassThroughTests - { - private const int DefaultStatusCode = 201; - - [Fact] - public async Task PassThrough_EmptyRequest_Success() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); - IDictionary emptyEnv = CreateEmptyRequest(); - await windowsAuth.Invoke(emptyEnv); - - Assert.Equal(DefaultStatusCode, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(0, responseHeaders.Count); - } - - [Fact] - public async Task PassThrough_BasicAuth_Success() - { - WindowsAuthMiddleware windowsAuth = new WindowsAuthMiddleware(SimpleApp); - IDictionary emptyEnv = CreateEmptyRequest("Authorization", "Basic blablabla"); - await windowsAuth.Invoke(emptyEnv); - - Assert.Equal(DefaultStatusCode, emptyEnv.Get("owin.ResponseStatusCode")); - var responseHeaders = emptyEnv.Get>("owin.ResponseHeaders"); - Assert.Equal(0, responseHeaders.Count); - } - - private IDictionary CreateEmptyRequest(string header = null, string value = null) - { - IDictionary env = new Dictionary(); - var requestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - env["owin.RequestHeaders"] = requestHeaders; - if (header != null) - { - requestHeaders[header] = new string[] { value }; - } - env["owin.ResponseHeaders"] = new Dictionary(StringComparer.OrdinalIgnoreCase); - env["server.OnSendingHeaders"] = new Action, object>((a, b) => { }); - return env; - } - - private Task SimpleApp(IDictionary env) - { - env["owin.ResponseStatusCode"] = DefaultStatusCode; - return Task.FromResult(null); - } - } -} diff --git a/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs b/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs deleted file mode 100644 index c0ff848336..0000000000 --- a/test/Microsoft.AspNet.Security.Windows.Test/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Microsoft.AspNet.Security.Windows.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Microsoft.AspNet.Security.Windows.Tests")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("334c99b0-a718-4cda-9ca0-d5a45c3a32b0")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.5")] -[assembly: AssemblyVersion("0.5")] -[assembly: AssemblyFileVersion("0.5.40117.0")] diff --git a/test/Microsoft.AspNet.Security.Windows.Test/project.json b/test/Microsoft.AspNet.Security.Windows.Test/project.json deleted file mode 100644 index f4e5ecfa6f..0000000000 --- a/test/Microsoft.AspNet.Security.Windows.Test/project.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNet.Security.Windows" : "", - "Microsoft.AspNet.Server.WebListener" : "", - "xunit.abstractions": "2.0.0-aspnet-*", - "xunit.assert": "2.0.0-aspnet-*", - "xunit.core": "2.0.0-aspnet-*", - "xunit.execution": "2.0.0-aspnet-*" - }, - "frameworks": { - "aspnet50": { - "dependencies": { - "System.Net.Http": "", - "System.Net.Http.WebRequest": "" - } - } - } -} From b7fb516aac4f6a97ce3cfa65494209e675256432 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 17 Oct 2014 10:42:51 -0700 Subject: [PATCH 129/597] Update Claims dependency. --- samples/HelloWorld/project.json | 2 +- samples/SelfHostServer/Startup.cs | 1 - src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/WebListener.cs | 3 --- src/Microsoft.Net.Http.Server/project.json | 2 +- 5 files changed, 3 insertions(+), 7 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 6f76aa53bc..9ef42357b6 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -9,7 +9,7 @@ "System.Collections": "4.0.10-beta-*", "System.Console": "4.0.0-beta-*", "System.Globalization": "4.0.10-beta-*", - "System.IO": "4.0.0-beta-*", + "System.IO": "4.0.10-beta-*", "System.Runtime": "4.0.20-beta-*", "System.Threading.Tasks": "4.0.10-beta-*" } diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index f4302222b9..f037e486bb 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -37,7 +37,6 @@ namespace SelfHostServer { if (context.IsWebSocketRequest) { - Console.WriteLine("WebSocket"); byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); WebSocket webSocket = await context.AcceptWebSocketAsync(); await webSocket.SendAsync(new ArraySegment(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None); diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 59de096b54..f39754f666 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -32,7 +32,7 @@ "System.Runtime.Extensions": "4.0.10-beta-*", "System.Runtime.Handles": "4.0.0-beta-*", "System.Runtime.InteropServices": "4.0.20-beta-*", - "System.Security.Claims": "1.0.0-*", + "System.Security.Claims": "4.0.0-beta-*", "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", "System.Security.Principal": "4.0.0-beta-*", "System.Text.Encoding": "4.0.10-beta-*", diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 70755ec5d3..57bafd0c49 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -27,7 +27,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; using System.Threading; @@ -36,8 +35,6 @@ using Microsoft.Framework.Logging; namespace Microsoft.Net.Http.Server { - using AppFunc = Func; - /// /// An HTTP server wrapping the Http.Sys APIs that accepts requests. /// diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 6be4acb186..01dab743c5 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -30,7 +30,7 @@ "System.Runtime.Extensions": "4.0.10-beta-*", "System.Runtime.Handles": "4.0.0-beta-*", "System.Runtime.InteropServices": "4.0.20-beta-*", - "System.Security.Claims": "1.0.0-*", + "System.Security.Claims": "4.0.0-beta-*", "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", "System.Security.Principal": "4.0.0-beta-*", "System.Text.Encoding": "4.0.10-beta-*", From a42a069dcf6c61bd61dbde7be72c992be94f9676 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 20 Oct 2014 10:34:46 -0700 Subject: [PATCH 130/597] Enable WindowsIdentity for CoreCLR. --- src/Microsoft.Net.Http.Server/AuthenticationManager.cs | 4 ---- src/Microsoft.Net.Http.Server/project.json | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 26670dfa48..9be0a01897 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -163,9 +163,7 @@ namespace Microsoft.Net.Http.Server && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { -#if !ASPNETCORE50 return true; -#endif } return false; } @@ -176,10 +174,8 @@ namespace Microsoft.Net.Http.Server && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { -#if !ASPNETCORE50 return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken, GetAuthTypeFromRequest(requestInfo->pInfo->AuthType).ToString())); -#endif } return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 01dab743c5..0b54d7ca45 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -33,6 +33,7 @@ "System.Security.Claims": "4.0.0-beta-*", "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", "System.Security.Principal": "4.0.0-beta-*", + "System.Security.Principal.Windows": "4.0.0-beta-*", "System.Text.Encoding": "4.0.10-beta-*", "System.Text.Encoding.Extensions": "4.0.10-beta-*", "System.Threading": "4.0.0-beta-*", From 84f98d715015dc72eb822b46fd36192dfbd50e11 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 21 Oct 2014 12:48:27 -0700 Subject: [PATCH 131/597] Updating build.sh to work on Mono --- build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index 4323aefc48..c7873ef58e 100644 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild @@ -28,7 +28,7 @@ if test ! -d packages/KoreBuild; then fi if ! type k > /dev/null 2>&1; then - source setup/kvm.sh + source packages/KoreBuild/build/kvm.sh fi if ! type k > /dev/null 2>&1; then From 10ef1b33c100431ef0b07c9958a5dc5092e015fd Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 24 Oct 2014 00:04:46 -0700 Subject: [PATCH 132/597] Reacting to System.Collections.Concurrent version change --- .../project.json | 27 ------------------- src/Microsoft.Net.Http.Server/project.json | 27 +------------------ src/Microsoft.Net.WebSockets/project.json | 12 --------- .../project.json | 9 +------ 4 files changed, 2 insertions(+), 73 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index f39754f666..bcff27c2cb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -15,33 +15,6 @@ "frameworks": { "aspnet50": { }, "aspnetcore50": { - "dependencies": { - "Microsoft.Win32.Primitives": "4.0.0-beta-*", - "System.Collections": "4.0.10-beta-*", - "System.Collections.Concurrent": "4.0.0-beta-*", - "System.Diagnostics.Contracts": "4.0.0-beta-*", - "System.Diagnostics.Debug": "4.0.10-beta-*", - "System.Diagnostics.Tools": "4.0.0-beta-*", - "System.Globalization": "4.0.10-beta-*", - "System.IO": "4.0.10-beta-*", - "System.Linq": "4.0.0-beta-*", - "System.Net.Primitives": "4.0.10-beta-*", - "System.Reflection": "4.0.10-beta-*", - "System.Resources.ResourceManager": "4.0.0-beta-*", - "System.Runtime": "4.0.20-beta-*", - "System.Runtime.Extensions": "4.0.10-beta-*", - "System.Runtime.Handles": "4.0.0-beta-*", - "System.Runtime.InteropServices": "4.0.20-beta-*", - "System.Security.Claims": "4.0.0-beta-*", - "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", - "System.Security.Principal": "4.0.0-beta-*", - "System.Text.Encoding": "4.0.10-beta-*", - "System.Text.Encoding.Extensions": "4.0.10-beta-*", - "System.Threading": "4.0.0-beta-*", - "System.Threading.Overlapped": "4.0.0-beta-*", - "System.Threading.Tasks": "4.0.10-beta-*", - "System.Threading.ThreadPool": "4.0.10-beta-*" - } } } } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 0b54d7ca45..dbfd1b9d69 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -12,34 +12,9 @@ "aspnet50": { }, "aspnetcore50": { "dependencies": { - "Microsoft.Net.WebSocketAbstractions": "1.0.0-*", - "Microsoft.Win32.Primitives": "4.0.0-beta-*", - "System.Collections": "4.0.10-beta-*", - "System.Collections.Concurrent": "4.0.0-beta-*", - "System.Diagnostics.Contracts": "4.0.0-beta-*", - "System.Diagnostics.Debug": "4.0.10-beta-*", - "System.Diagnostics.Tools": "4.0.0-beta-*", - "System.Globalization": "4.0.10-beta-*", - "System.IO": "4.0.10-beta-*", "System.IO.FileSystem": "4.0.0-beta-*", - "System.Linq": "4.0.0-beta-*", - "System.Net.Primitives": "4.0.10-beta-*", - "System.Reflection": "4.0.10-beta-*", - "System.Resources.ResourceManager": "4.0.0-beta-*", - "System.Runtime": "4.0.20-beta-*", - "System.Runtime.Extensions": "4.0.10-beta-*", - "System.Runtime.Handles": "4.0.0-beta-*", - "System.Runtime.InteropServices": "4.0.20-beta-*", - "System.Security.Claims": "4.0.0-beta-*", "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", - "System.Security.Principal": "4.0.0-beta-*", - "System.Security.Principal.Windows": "4.0.0-beta-*", - "System.Text.Encoding": "4.0.10-beta-*", - "System.Text.Encoding.Extensions": "4.0.10-beta-*", - "System.Threading": "4.0.0-beta-*", - "System.Threading.Overlapped": "4.0.0-beta-*", - "System.Threading.Tasks": "4.0.10-beta-*", - "System.Threading.ThreadPool": "4.0.10-beta-*" + "System.Security.Principal.Windows": "4.0.0-beta-*" } } } diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 6280518ea0..756bcdce7d 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -8,26 +8,14 @@ "net45": { }, "aspnetcore50": { "dependencies": { - "Microsoft.Win32.Primitives": "4.0.0-beta-*", "System.Collections": "4.0.10-beta-*", - "System.Collections.Concurrent": "4.0.0-beta-*", "System.Diagnostics.Contracts": "4.0.0-beta-*", - "System.Diagnostics.Debug": "4.0.10-beta-*", "System.Diagnostics.Tools": "4.0.0-beta-*", - "System.Globalization": "4.0.10-beta-*", "System.IO": "4.0.10-beta-*", "System.Linq": "4.0.0-beta-*", - "System.Net.Primitives": "4.0.10-beta-*", - "System.Reflection": "4.0.10-beta-*", "System.Resources.ResourceManager": "4.0.0-beta-*", - "System.Runtime": "4.0.20-beta-*", "System.Runtime.Extensions": "4.0.10-beta-*", - "System.Runtime.Handles": "4.0.0-beta-*", - "System.Runtime.InteropServices": "4.0.20-beta-*", - "System.Security.Cryptography.Encryption": "4.0.0-beta-*", "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", - "System.Security.Principal": "4.0.0-beta-*", - "System.Text.Encoding": "4.0.10-beta-*", "System.Text.Encoding.Extensions": "4.0.10-beta-*", "System.Threading": "4.0.0-beta-*", "System.Threading.Overlapped": "4.0.0-beta-*", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index a8ab3c7d16..f3ed4c727f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -3,15 +3,8 @@ "test": "Xunit.KRunner" }, "dependencies": { - "Microsoft.AspNet.FeatureModel": "1.0.0-*", - "Microsoft.AspNet.Hosting": "1.0.0-*", - "Microsoft.AspNet.Http": "1.0.0-*", - "Microsoft.AspNet.HttpFeature": "1.0.0-*", "Microsoft.AspNet.PipelineCore": "1.0.0-*", - "Microsoft.AspNet.Server.WebListener": "", - "Microsoft.Framework.ConfigurationModel": "1.0.0-*", - "Microsoft.Framework.Logging": "1.0.0-*", - "Microsoft.Net.Http.Server": "1.0.0-*", + "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Xunit.KRunner": "1.0.0-*" }, "frameworks": { From 733eb85b5461ebf3ea3541c1a82d5f567aead582 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 24 Oct 2014 00:23:04 -0700 Subject: [PATCH 133/597] Adding reference to allow building --- src/Microsoft.Net.Http.Server/project.json | 2 ++ src/Microsoft.Net.WebSockets/project.json | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index dbfd1b9d69..4c08723366 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -12,6 +12,8 @@ "aspnet50": { }, "aspnetcore50": { "dependencies": { + "Microsoft.Win32.Primitives": "4.0.0-beta-*", + "System.Diagnostics.Debug": "4.0.10-beta-*", "System.IO.FileSystem": "4.0.0-beta-*", "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", "System.Security.Principal.Windows": "4.0.0-beta-*" diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 756bcdce7d..0ebe64350a 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -13,6 +13,7 @@ "System.Diagnostics.Tools": "4.0.0-beta-*", "System.IO": "4.0.10-beta-*", "System.Linq": "4.0.0-beta-*", + "System.Net.Primitives": "4.0.10-beta-*", "System.Resources.ResourceManager": "4.0.0-beta-*", "System.Runtime.Extensions": "4.0.10-beta-*", "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", From 6e2b94dde3b6b64dc62e5c00ebf1bc096fbb7e50 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 24 Oct 2014 12:15:07 -0700 Subject: [PATCH 134/597] #76 - Suppress shutdown error logs. --- src/Microsoft.AspNet.Server.WebListener/LogHelper.cs | 5 +++++ .../MessagePump.cs | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs index 28559308b6..2501c20620 100644 --- a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -64,6 +64,11 @@ namespace Microsoft.AspNet.Server.WebListener } } + internal static void LogVerbose(ILogger logger, string location, Exception exception) + { + LogVerbose(logger, location + "; " + exception.ToString()); + } + internal static void LogException(ILogger logger, string location, Exception exception) { if (logger == null) diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index c02513be2f..a6089cb400 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -123,8 +123,15 @@ namespace Microsoft.AspNet.Server.WebListener } catch (Exception exception) { - LogHelper.LogException(_logger, "ListenForNextRequestAsync", exception); - Contract.Assert(!_listener.IsListening); + Contract.Assert(_stopping); + if (_stopping) + { + LogHelper.LogVerbose(_logger, "ListenForNextRequestAsync-Stopping", exception); + } + else + { + LogHelper.LogException(_logger, "ListenForNextRequestAsync", exception); + } return; } try @@ -197,6 +204,7 @@ namespace Microsoft.AspNet.Server.WebListener public void Dispose() { + LogHelper.LogInfo(_logger, "Stop"); _stopping = true; // Wait for active requests to drain if (_outstandingRequests > 0) From 01a4d8d5bbfea8dfedaf780b2bc10bc1d2005b27 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 31 Oct 2014 02:46:22 -0700 Subject: [PATCH 135/597] Added package descriptions --- src/Microsoft.AspNet.Server.WebListener/project.json | 1 + src/Microsoft.Net.Http.Server/project.json | 1 + src/Microsoft.Net.WebSockets/project.json | 1 + 3 files changed, 3 insertions(+) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index f39754f666..4385fb5093 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,5 +1,6 @@ { "version": "1.0.0-*", + "description": "ASP.NET 5 self-host web server.", "dependencies": { "Microsoft.AspNet.FeatureModel": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 0b54d7ca45..97d0ba5627 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,5 +1,6 @@ { "version": "1.0.0-*", + "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Net.WebSockets": "1.0.0-*" diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 6280518ea0..15ebde6956 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,5 +1,6 @@ { "version": "1.0.0-*", + "description": "Implementation of WebSocket abstract base class. Used by WebListener.", "dependencies": { "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" }, From f19ae9828ce31c15daf5811e032b1aea3b929c75 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 6 Nov 2014 10:51:12 -0800 Subject: [PATCH 136/597] Updating to release NuGet.config --- NuGet.Config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.Config b/NuGet.Config index f41e9c631d..2d3b0cb857 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@  - + From f6c1a559a0abaa8639a0616f3ead08cf12c3051b Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 30 Oct 2014 12:11:34 -0700 Subject: [PATCH 137/597] Add new HeadersSent API. --- .../FeatureContext.cs | 5 +++++ .../MessagePump.cs | 2 +- .../RequestProcessing/RequestContext.cs | 2 +- .../RequestProcessing/Response.cs | 4 ++-- .../RequestProcessing/ResponseStream.cs | 14 +++++++------- .../ResponseHeaderTests.cs | 4 ++++ .../ResponseTests.cs | 1 + .../ResponseHeaderTests.cs | 4 ++++ 8 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index d27fb974da..af21159d7e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -348,6 +348,11 @@ namespace Microsoft.AspNet.Server.WebListener set { _responseHeaders = value; } } + bool IHttpResponseFeature.HeadersSent + { + get { return Response.HeadersSent; } + } + void IHttpResponseFeature.OnSendingHeaders(Action callback, object state) { Response.OnSendingHeaders(callback, state); diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index a6089cb400..f376c034af 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -168,7 +168,7 @@ namespace Microsoft.AspNet.Server.WebListener catch (Exception ex) { LogHelper.LogException(_logger, "ProcessRequestAsync", ex); - if (requestContext.Response.SentHeaders) + if (requestContext.Response.HeadersSent) { requestContext.Abort(); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 37102f41a2..37862cc392 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -145,7 +145,7 @@ namespace Microsoft.Net.Http.Server public Task UpgradeAsync() { - if (!IsUpgradableRequest || _response.SentHeaders) + if (!IsUpgradableRequest || _response.HeadersSent) { throw new InvalidOperationException(); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 72aa46bd8c..21149425af 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -297,7 +297,7 @@ namespace Microsoft.Net.Http.Server } } - public bool SentHeaders + public bool HeadersSent { get { @@ -356,7 +356,7 @@ namespace Microsoft.Net.Http.Server UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags, bool isOpaqueUpgrade) { - Debug.Assert(!SentHeaders, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); + Debug.Assert(!HeadersSent, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); // TODO: Verbose log headers _responseState = ResponseState.SentHeaders; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 5572e22e5a..cbe64f4330 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -94,7 +94,7 @@ namespace Microsoft.Net.Http.Server // Send headers public override void Flush() { - if (_closed || _requestContext.Response.SentHeaders) + if (_closed || _requestContext.Response.HeadersSent) { return; } @@ -127,7 +127,7 @@ namespace Microsoft.Net.Http.Server // Send headers public override Task FlushAsync(CancellationToken cancellationToken) { - if (_closed || _requestContext.Response.SentHeaders) + if (_closed || _requestContext.Response.HeadersSent) { return Helpers.CompletedTask(); } @@ -275,7 +275,7 @@ namespace Microsoft.Net.Http.Server uint dataToWrite = (uint)size; SafeLocalFree bufferAsIntPtr = null; IntPtr pBufferAsIntPtr = IntPtr.Zero; - bool sentHeaders = _requestContext.Response.SentHeaders; + bool sentHeaders = _requestContext.Response.HeadersSent; try { if (size == 0) @@ -398,7 +398,7 @@ namespace Microsoft.Net.Http.Server uint statusCode; uint bytesSent = 0; flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - bool sentHeaders = _requestContext.Response.SentHeaders; + bool sentHeaders = _requestContext.Response.HeadersSent; ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, state, callback, buffer, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders); // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite. @@ -543,7 +543,7 @@ namespace Microsoft.Net.Http.Server uint statusCode; uint bytesSent = 0; flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - bool sentHeaders = _requestContext.Response.SentHeaders; + bool sentHeaders = _requestContext.Response.HeadersSent; ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, buffer, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, cancellationRegistration); // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite. @@ -649,7 +649,7 @@ namespace Microsoft.Net.Http.Server uint statusCode; uint bytesSent = 0; flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - bool sentHeaders = _requestContext.Response.SentHeaders; + bool sentHeaders = _requestContext.Response.HeadersSent; ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, fileName, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, cancellationRegistration); @@ -768,7 +768,7 @@ namespace Microsoft.Net.Http.Server LogHelper.LogError(_requestContext.Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length."); return; } - bool sentHeaders = _requestContext.Response.SentHeaders; + bool sentHeaders = _requestContext.Response.HeadersSent; if (sentHeaders && _leftToWrite == 0) { return; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 66b18b3364..12cf0daf8e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -245,7 +245,9 @@ namespace Microsoft.AspNet.Server.WebListener responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); var body = responseInfo.Body; + Assert.False(responseInfo.HeadersSent); body.Flush(); + Assert.True(responseInfo.HeadersSent); Assert.Throws(() => responseInfo.StatusCode = 404); Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); return Task.FromResult(0); @@ -275,7 +277,9 @@ namespace Microsoft.AspNet.Server.WebListener responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); var body = responseInfo.Body; + Assert.False(responseInfo.HeadersSent); await body.FlushAsync(); + Assert.True(responseInfo.HeadersSent); Assert.Throws(() => responseInfo.StatusCode = 404); Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); })) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index 6d7d13af0c..5505163782 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -36,6 +36,7 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); Assert.Equal(200, httpContext.Response.StatusCode); + Assert.False(httpContext.Response.HeadersSent); return Task.FromResult(0); })) { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index 3059532f5d..2fc83a613e 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -232,7 +232,9 @@ namespace Microsoft.Net.Http.Server responseHeaders.SetValues("Custom1", "value1a", "value1b"); responseHeaders.SetValues("Custom2", "value2a, value2b"); var body = context.Response.Body; + Assert.False(context.Response.HeadersSent); body.Flush(); + Assert.True(context.Response.HeadersSent); var ex = Assert.Throws(() => context.Response.StatusCode = 404); Assert.Equal("Headers already sent.", ex.Message); ex = Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); @@ -266,7 +268,9 @@ namespace Microsoft.Net.Http.Server responseHeaders.SetValues("Custom1", "value1a", "value1b"); responseHeaders.SetValues("Custom2", "value2a, value2b"); var body = context.Response.Body; + Assert.False(context.Response.HeadersSent); await body.FlushAsync(); + Assert.True(context.Response.HeadersSent); var ex = Assert.Throws(() => context.Response.StatusCode = 404); Assert.Equal("Headers already sent.", ex.Message); ex = Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); From 15344d8d7a3ee2b196e4782ab702f1b5fae057bc Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Wed, 12 Nov 2014 15:39:40 -0800 Subject: [PATCH 138/597] Update KProj to the latest format --- samples/HelloWorld/HelloWorld.kproj | 18 ++++++---------- samples/SelfHostServer/SelfHostServer.kproj | 21 ++++++------------- .../Microsoft.AspNet.Server.WebListener.kproj | 18 ++++++---------- .../Microsoft.Net.Http.Server.kproj | 19 ++++++----------- .../Microsoft.Net.WebSockets.kproj | 19 ++++++----------- ...t.Server.WebListener.FunctionalTests.kproj | 19 ++++++----------- ...soft.Net.Http.Server.FunctionalTests.kproj | 19 ++++++----------- 7 files changed, 42 insertions(+), 91 deletions(-) diff --git a/samples/HelloWorld/HelloWorld.kproj b/samples/HelloWorld/HelloWorld.kproj index cad0b80483..a1d060ee0b 100644 --- a/samples/HelloWorld/HelloWorld.kproj +++ b/samples/HelloWorld/HelloWorld.kproj @@ -1,20 +1,14 @@ - - + + - 12.0 + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6daf3e6b-8e1b-4e6e-b9fe-7b1e5fdb7db4 - Library - - - - - - - 2.0 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ - \ No newline at end of file + diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index efbadb0189..82caabdf9d 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -1,23 +1,14 @@ - - + + - 12.0 + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 1236f93a-ac5c-4a77-9477-c88f040151ca - Library - - - - - - - 2.0 - - - 57504 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ - \ No newline at end of file + diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj index 72e20d0eb5..24aa1efd5a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -1,20 +1,14 @@ - - + + - 12.0 + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) b9f45f9d-d206-47f0-8e5f-54ce2f0bdf92 - Library - - - - - - - 2.0 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ - \ No newline at end of file + diff --git a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj index 57ece075d0..e08f2e689d 100644 --- a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj +++ b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj @@ -1,21 +1,14 @@ - - + + - 12.0 + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 - Library - net45 - - - - - - - 2.0 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ - \ No newline at end of file + diff --git a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj index e3d0679128..c1a58840d9 100644 --- a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj +++ b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj @@ -1,21 +1,14 @@ - - + + - 12.0 + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) e788aeae-2cb4-4bfa-8746-d0bb7e93a1bb - Library - net45 - - - - - - - 2.0 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ - \ No newline at end of file + diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj index 4c049bd5dc..dba145f8b9 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj @@ -1,21 +1,14 @@ - - + + - 12.0 + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 4492ff4c-9032-411d-853f-46b01755e504 - Library - net45 - - - - - - - 2.0 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ - \ No newline at end of file + diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj index 5f105dd1f6..73faf72fd3 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj @@ -1,21 +1,14 @@ - - + + - 12.0 + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) dcb6e0b1-223d-44e6-8696-4767e5b6e6a1 - Library - net45 - - - - - - - 2.0 + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ - \ No newline at end of file + From 46a11be2edf57a54d6ebec42e0bba156c3eee272 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 21 Oct 2014 12:20:17 -0700 Subject: [PATCH 139/597] #39 - Hot add/remove prefixes. #13 - Support Add/Remove(string). --- .../RequestProcessing/Request.cs | 2 +- src/Microsoft.Net.Http.Server/UrlPrefix.cs | 2 +- .../UrlPrefixCollection.cs | 171 ++++++++++++++++++ src/Microsoft.Net.Http.Server/WebListener.cs | 95 ++-------- .../ServerTests.cs | 63 +++++++ 5 files changed, 247 insertions(+), 86 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 015cb98e47..750d4425d3 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -106,7 +106,7 @@ namespace Microsoft.Net.Http.Server _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } - UrlPrefix prefix = httpContext.Server.UrlPrefixes[(int)_contextId]; + UrlPrefix prefix = httpContext.Server.UrlPrefixes.GetPrefix((int)_contextId); string orriginalPath = RequestPath; // These paths are both unescaped already. diff --git a/src/Microsoft.Net.Http.Server/UrlPrefix.cs b/src/Microsoft.Net.Http.Server/UrlPrefix.cs index 24cf55fd0e..0c53cc67c9 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefix.cs @@ -166,7 +166,7 @@ namespace Microsoft.Net.Http.Server public override bool Equals(object obj) { - return string.Equals(Whole, obj as string, StringComparison.OrdinalIgnoreCase); + return string.Equals(Whole, Convert.ToString(obj), StringComparison.OrdinalIgnoreCase); } public override int GetHashCode() diff --git a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs new file mode 100644 index 0000000000..9165960a63 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Microsoft.Net.Http.Server +{ + /// + /// A collection or URL prefixes + /// + public class UrlPrefixCollection : ICollection + { + private readonly WebListener _webListener; + private readonly IDictionary _prefixes = new Dictionary(1); + private int _nextId = 1; + + internal UrlPrefixCollection(WebListener webListener) + { + _webListener = webListener; + } + + public int Count + { + get { return _prefixes.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public void Add(string prefix) + { + Add(UrlPrefix.Create(prefix)); + } + + public void Add(UrlPrefix item) + { + var id = _nextId++; + if (_webListener.IsListening) + { + RegisterPrefix(item.Whole, id); + } + _prefixes.Add(id, item); + } + + internal UrlPrefix GetPrefix(int id) + { + return _prefixes[id]; + } + + public void Clear() + { + if (_webListener.IsListening) + { + UnregisterAllPrefixes(); + } + _prefixes.Clear(); + } + + public bool Contains(UrlPrefix item) + { + return _prefixes.Values.Contains(item); + } + + public void CopyTo(UrlPrefix[] array, int arrayIndex) + { + _prefixes.Values.CopyTo(array, arrayIndex); + } + + public bool Remove(string prefix) + { + return Remove(UrlPrefix.Create(prefix)); + } + + public bool Remove(UrlPrefix item) + { + int? id = null; + foreach (var pair in _prefixes) + { + if (pair.Value.Equals(item)) + { + id = pair.Key; + if (_webListener.IsListening) + { + UnregisterPrefix(pair.Value.Whole); + } + } + } + if (id.HasValue) + { + _prefixes.Remove(id.Value); + return true; + } + return false; + } + + public IEnumerator GetEnumerator() + { + return _prefixes.Values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + internal void RegisterAllPrefixes() + { + // go through the uri list and register for each one of them + foreach (var pair in _prefixes) + { + // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. + RegisterPrefix(pair.Value.Whole, pair.Key); + } + } + + internal void UnregisterAllPrefixes() + { + // go through the uri list and unregister for each one of them + foreach (var prefix in _prefixes.Values) + { + // ignore possible failures + UnregisterPrefix(prefix.Whole); + } + } + + private void RegisterPrefix(string uriPrefix, int contextId) + { + uint statusCode = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup( + _webListener.UrlGroupId, + uriPrefix, + (ulong)contextId, + 0); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS) + { + throw new WebListenerException((int)statusCode, String.Format(Resources.Exception_PrefixAlreadyRegistered, uriPrefix)); + } + else + { + throw new WebListenerException((int)statusCode); + } + } + } + + private bool UnregisterPrefix(string uriPrefix) + { + uint statusCode = 0; + + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup( + _webListener.UrlGroupId, + uriPrefix, + 0); + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) + { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 57bafd0c49..54cb36fd20 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -85,7 +85,7 @@ namespace Microsoft.Net.Http.Server private object _internalLock; - private List _urlPrefixes = new List(); + private UrlPrefixCollection _urlPrefixes; // The native request queue private long? _requestQueueLength; @@ -103,6 +103,7 @@ namespace Microsoft.Net.Http.Server _state = State.Stopped; _internalLock = new object(); + _urlPrefixes = new UrlPrefixCollection(this); _timeoutManager = new TimeoutManager(this); _authManager = new AuthenticationManager(this); _connectionCancellationTokens = new ConcurrentDictionary(); @@ -120,7 +121,7 @@ namespace Microsoft.Net.Http.Server get { return _logger; } } - public List UrlPrefixes + public UrlPrefixCollection UrlPrefixes { get { return _urlPrefixes; } } @@ -133,6 +134,11 @@ namespace Microsoft.Net.Http.Server } } + internal ulong UrlGroupId + { + get { return _urlGroupId; } + } + /// /// Exposes the Http.Sys timeout configurations. These may also be configured in the registry. /// @@ -258,29 +264,6 @@ namespace Microsoft.Net.Http.Server } } - internal void RemoveAll(bool clear) - { - CheckDisposed(); - // go through the uri list and unregister for each one of them - if (_urlPrefixes.Count > 0) - { - LogHelper.LogInfo(_logger, "RemoveAll"); - if (_state == State.Started) - { - foreach (UrlPrefix registeredPrefix in _urlPrefixes) - { - // ignore possible failures - InternalRemovePrefix(registeredPrefix.Whole); - } - } - - if (clear) - { - _urlPrefixes.Clear(); - } - } - } - private IntPtr DangerousGetHandle() { return _requestQueueHandle.DangerousGetHandle(); @@ -379,7 +362,7 @@ namespace Microsoft.Net.Http.Server // All resources are set up correctly. Now add all prefixes. try { - AddAllPrefixes(); + _urlPrefixes.RegisterAllPrefixes(); } catch (WebListenerException) { @@ -489,7 +472,7 @@ namespace Microsoft.Net.Http.Server } LogHelper.LogInfo(_logger, "Stop"); - RemoveAll(false); + _urlPrefixes.UnregisterAllPrefixes(); _state = State.Stopped; @@ -586,62 +569,6 @@ namespace Microsoft.Net.Http.Server } } - private uint InternalAddPrefix(string uriPrefix, int contextId) - { - uint statusCode = 0; - - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup( - _urlGroupId, - uriPrefix, - (ulong)contextId, - 0); - - return statusCode; - } - - private bool InternalRemovePrefix(string uriPrefix) - { - uint statusCode = 0; - - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup( - _urlGroupId, - uriPrefix, - 0); - - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) - { - return false; - } - return true; - } - - private void AddAllPrefixes() - { - // go through the uri list and register for each one of them - if (_urlPrefixes.Count > 0) - { - for (int i = 0; i < _urlPrefixes.Count; i++) - { - // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. - UrlPrefix registeredPrefix = _urlPrefixes[i]; - uint statusCode = InternalAddPrefix(registeredPrefix.Whole, i); - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS) - { - throw new WebListenerException((int)statusCode, String.Format(Resources.Exception_PrefixAlreadyRegistered, registeredPrefix.Whole)); - } - else - { - throw new WebListenerException((int)statusCode); - } - } - } - } - } - internal unsafe bool ValidateRequest(NativeRequestContext requestMemory) { // Block potential DOS attacks @@ -713,7 +640,7 @@ namespace Microsoft.Net.Http.Server private CancellationToken GetConnectionCancellation(ulong connectionId) { - // Read case is performance senstive + // Read case is performance sensitive ConnectionCancellation cancellation; if (!_connectionCancellationTokens.TryGetValue(connectionId, out cancellation)) { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 12e9282073..8b9ed10838 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -181,6 +181,69 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task Server_HotAddPrefix_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + Assert.Equal(string.Empty, context.Request.PathBase); + Assert.Equal("/", context.Request.Path); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(string.Empty, response); + + address += "pathbase/"; + server.UrlPrefixes.Add(address); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + Assert.Equal("/pathbase", context.Request.PathBase); + Assert.Equal("/", context.Request.Path); + context.Dispose(); + + response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task Server_HotRemovePrefix_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + address += "pathbase/"; + server.UrlPrefixes.Add(address); + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + Assert.Equal("/pathbase", context.Request.PathBase); + Assert.Equal("/", context.Request.Path); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(string.Empty, response); + + Assert.True(server.UrlPrefixes.Remove(address)); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + Assert.Equal(string.Empty, context.Request.PathBase); + Assert.Equal("/pathbase/", context.Request.Path); + context.Dispose(); + + response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + private async Task SendRequestAsync(string uri) { ServicePointManager.DefaultConnectionLimit = 100; From ecf9454efef12a25ba4f309dfdc3cbb45e86f4e0 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 14 Nov 2014 12:17:35 -0800 Subject: [PATCH 140/597] Make prefix add & remove thread safe. --- .../UrlPrefixCollection.cs | 99 ++++++++++++------- 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs index 9165960a63..0908630137 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs @@ -15,7 +15,7 @@ namespace Microsoft.Net.Http.Server private readonly WebListener _webListener; private readonly IDictionary _prefixes = new Dictionary(1); private int _nextId = 1; - + internal UrlPrefixCollection(WebListener webListener) { _webListener = webListener; @@ -23,7 +23,13 @@ namespace Microsoft.Net.Http.Server public int Count { - get { return _prefixes.Count; } + get + { + lock (_prefixes) + { + return _prefixes.Count; + } + } } public bool IsReadOnly @@ -38,36 +44,51 @@ namespace Microsoft.Net.Http.Server public void Add(UrlPrefix item) { - var id = _nextId++; - if (_webListener.IsListening) + lock (_prefixes) { - RegisterPrefix(item.Whole, id); + var id = _nextId++; + if (_webListener.IsListening) + { + RegisterPrefix(item.Whole, id); + } + _prefixes.Add(id, item); } - _prefixes.Add(id, item); } internal UrlPrefix GetPrefix(int id) { - return _prefixes[id]; + lock (_prefixes) + { + return _prefixes[id]; + } } public void Clear() { - if (_webListener.IsListening) + lock (_prefixes) { - UnregisterAllPrefixes(); + if (_webListener.IsListening) + { + UnregisterAllPrefixes(); + } + _prefixes.Clear(); } - _prefixes.Clear(); } public bool Contains(UrlPrefix item) { - return _prefixes.Values.Contains(item); + lock (_prefixes) + { + return _prefixes.Values.Contains(item); + } } public void CopyTo(UrlPrefix[] array, int arrayIndex) { - _prefixes.Values.CopyTo(array, arrayIndex); + lock (_prefixes) + { + _prefixes.Values.CopyTo(array, arrayIndex); + } } public bool Remove(string prefix) @@ -77,29 +98,35 @@ namespace Microsoft.Net.Http.Server public bool Remove(UrlPrefix item) { - int? id = null; - foreach (var pair in _prefixes) + lock (_prefixes) { - if (pair.Value.Equals(item)) + int? id = null; + foreach (var pair in _prefixes) { - id = pair.Key; - if (_webListener.IsListening) + if (pair.Value.Equals(item)) { - UnregisterPrefix(pair.Value.Whole); + id = pair.Key; + if (_webListener.IsListening) + { + UnregisterPrefix(pair.Value.Whole); + } } } + if (id.HasValue) + { + _prefixes.Remove(id.Value); + return true; + } + return false; } - if (id.HasValue) - { - _prefixes.Remove(id.Value); - return true; - } - return false; } public IEnumerator GetEnumerator() { - return _prefixes.Values.GetEnumerator(); + lock (_prefixes) + { + return _prefixes.Values.GetEnumerator(); + } } IEnumerator IEnumerable.GetEnumerator() @@ -109,21 +136,27 @@ namespace Microsoft.Net.Http.Server internal void RegisterAllPrefixes() { - // go through the uri list and register for each one of them - foreach (var pair in _prefixes) + lock (_prefixes) { - // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. - RegisterPrefix(pair.Value.Whole, pair.Key); + // go through the uri list and register for each one of them + foreach (var pair in _prefixes) + { + // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. + RegisterPrefix(pair.Value.Whole, pair.Key); + } } } internal void UnregisterAllPrefixes() { - // go through the uri list and unregister for each one of them - foreach (var prefix in _prefixes.Values) + lock (_prefixes) { - // ignore possible failures - UnregisterPrefix(prefix.Whole); + // go through the uri list and unregister for each one of them + foreach (var prefix in _prefixes.Values) + { + // ignore possible failures + UnregisterPrefix(prefix.Whole); + } } } From 8caec74f03fb5622040245912f782d94dcfe54ad Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 14 Nov 2014 16:35:05 -0800 Subject: [PATCH 141/597] Add a HotAdd/Remove prefix sample. --- WebListener.sln | 17 ++++- samples/HotAddSample/HotAddSample.kproj | 21 ++++++ samples/HotAddSample/Startup.cs | 87 +++++++++++++++++++++++++ samples/HotAddSample/project.json | 23 +++++++ samples/SelfHostServer/project.json | 2 +- 5 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 samples/HotAddSample/HotAddSample.kproj create mode 100644 samples/HotAddSample/Startup.cs create mode 100644 samples/HotAddSample/project.json diff --git a/WebListener.sln b/WebListener.sln index c55169b1f2..ddac12e798 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22115.0 +VisualStudioVersion = 14.0.22310.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -30,6 +30,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution global.json = global.json EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HotAddSample", "samples\HotAddSample\HotAddSample.kproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -120,6 +122,18 @@ Global {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|x86.ActiveCfg = Release|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|x86.ActiveCfg = Debug|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|x86.Build.0 = Debug|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|Any CPU.Build.0 = Release|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|x86.ActiveCfg = Release|Any CPU + {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -133,5 +147,6 @@ Global {4492FF4C-9032-411D-853F-46B01755E504} = {E183C826-1360-4DFF-9994-F33CED5C8525} {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1} = {E183C826-1360-4DFF-9994-F33CED5C8525} + {8BFA392A-8B67-4454-916B-67C545EDFAEF} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} EndGlobalSection EndGlobal diff --git a/samples/HotAddSample/HotAddSample.kproj b/samples/HotAddSample/HotAddSample.kproj new file mode 100644 index 0000000000..89120d77f5 --- /dev/null +++ b/samples/HotAddSample/HotAddSample.kproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 8bfa392a-8b67-4454-916b-67c545edfaef + HotAddSample + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + 59517 + + web + + + \ No newline at end of file diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs new file mode 100644 index 0000000000..2092308438 --- /dev/null +++ b/samples/HotAddSample/Startup.cs @@ -0,0 +1,87 @@ +using System; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Server.WebListener; + +namespace HotAddSample +{ + // This sample shows how to dynamically add or remove prefixes for the underlying server. + // Be careful not to remove the prefix you're currently accessing because the connection + // will be reset before the end of the request. + public class Startup + { + public void Configure(IApplicationBuilder app) + { + var server = (ServerInformation)app.Server; + var listener = server.Listener; + listener.UrlPrefixes.Add("http://localhost:12346/pathBase/"); + + app.Use(async (context, next) => + { + // Note: To add any prefix other than localhost you must run this sample as an administrator. + var toAdd = context.Request.Query["add"]; + if (!string.IsNullOrEmpty(toAdd)) + { + context.Response.ContentType = "text/html"; + await context.Response.WriteAsync(""); + try + { + listener.UrlPrefixes.Add(toAdd); + await context.Response.WriteAsync("Added: " + toAdd); + } + catch (Exception ex) + { + await context.Response.WriteAsync("Error adding: " + toAdd + "
"); + await context.Response.WriteAsync(ex.ToString().Replace(Environment.NewLine, "
")); + } + await context.Response.WriteAsync("
back"); + await context.Response.WriteAsync(""); + return; + } + await next(); + }); + + app.Use(async (context, next) => + { + // Be careful not to remove the prefix you're currently accessing because the connection + // will be reset before the response is sent. + var toRemove = context.Request.Query["remove"]; + if (!string.IsNullOrEmpty(toRemove)) + { + context.Response.ContentType = "text/html"; + await context.Response.WriteAsync(""); + if (listener.UrlPrefixes.Remove(toRemove)) + { + await context.Response.WriteAsync("Removed: " + toRemove); + } + else + { + await context.Response.WriteAsync("Not found: " + toRemove); + } + await context.Response.WriteAsync("
back"); + await context.Response.WriteAsync(""); + return; + } + await next(); + }); + + app.Run(async context => + { + context.Response.ContentType = "text/html"; + await context.Response.WriteAsync(""); + await context.Response.WriteAsync("Listening on these prefixes:
"); + foreach (var prefix in listener.UrlPrefixes) + { + await context.Response.WriteAsync("" + prefix + " (remove)
"); + } + + await context.Response.WriteAsync("
"); + await context.Response.WriteAsync(""); + await context.Response.WriteAsync(""); + await context.Response.WriteAsync("
"); + + await context.Response.WriteAsync(""); + }); + } + } +} diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json new file mode 100644 index 0000000000..54bd01b3f5 --- /dev/null +++ b/samples/HotAddSample/project.json @@ -0,0 +1,23 @@ +{ + "webroot": "wwwroot", + "version": "1.0.0-*", + "exclude": [ + "wwwroot" + ], + "packExclude": [ + "**.kproj", + "**.user", + "**.vspscc" + ], + "dependencies": { + "Microsoft.AspNet.Hosting": "1.0.0-*", + "Microsoft.AspNet.Server.WebListener": "1.0.0-*" + }, + "commands": { + "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:12345" + }, + "frameworks" : { + "aspnet50" : { }, + "aspnetcore50" : { } + } +} diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index cbb2e6e7f1..5d32685c69 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -3,7 +3,7 @@ "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*" }, - "commands": { "web": "Microsoft.AspNet.Hosting --server=Microsoft.AspNet.Server.WebListener --server.urls=http://localhost:8080" }, + "commands": { "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:8080" }, "frameworks": { "aspnet50": { }, "aspnetcore50": { } From f6aa12cfa80753bc0c79b02ab7f8eb9a56e4a915 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Tue, 25 Nov 2014 11:08:17 -0800 Subject: [PATCH 142/597] Add schema version to kproj files --- samples/HelloWorld/HelloWorld.kproj | 3 +++ samples/HotAddSample/HotAddSample.kproj | 8 ++------ samples/SelfHostServer/SelfHostServer.kproj | 3 +++ .../Microsoft.AspNet.Server.WebListener.kproj | 3 +++ .../Microsoft.Net.Http.Server.kproj | 3 +++ .../Microsoft.Net.WebSockets.kproj | 3 +++ ...rosoft.AspNet.Server.WebListener.FunctionalTests.kproj | 3 +++ .../Microsoft.Net.Http.Server.FunctionalTests.kproj | 3 +++ 8 files changed, 23 insertions(+), 6 deletions(-) diff --git a/samples/HelloWorld/HelloWorld.kproj b/samples/HelloWorld/HelloWorld.kproj index a1d060ee0b..b617afbdb3 100644 --- a/samples/HelloWorld/HelloWorld.kproj +++ b/samples/HelloWorld/HelloWorld.kproj @@ -10,5 +10,8 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ + + 2.0 + diff --git a/samples/HotAddSample/HotAddSample.kproj b/samples/HotAddSample/HotAddSample.kproj index 89120d77f5..04ffc32bb5 100644 --- a/samples/HotAddSample/HotAddSample.kproj +++ b/samples/HotAddSample/HotAddSample.kproj @@ -1,4 +1,4 @@ - + 14.0 @@ -7,15 +7,11 @@ 8bfa392a-8b67-4454-916b-67c545edfaef - HotAddSample ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ 2.0 - 59517 - - web - \ No newline at end of file + diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index 82caabdf9d..2695c3ae40 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -10,5 +10,8 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ + + 2.0 + diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj index 24aa1efd5a..4292c1d7dc 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj @@ -10,5 +10,8 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ + + 2.0 + diff --git a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj index e08f2e689d..99200daf9a 100644 --- a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj +++ b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj @@ -10,5 +10,8 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ + + 2.0 + diff --git a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj index c1a58840d9..1f1ed03bcf 100644 --- a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj +++ b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj @@ -10,5 +10,8 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ + + 2.0 + diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj index dba145f8b9..4d35f3ef98 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj @@ -10,5 +10,8 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ + + 2.0 + diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj index 73faf72fd3..3d2f7da25f 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj @@ -10,5 +10,8 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ + + 2.0 + From 3fdf6563532b167de10106105a03c427ee72acc5 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 17 Nov 2014 10:00:24 -0800 Subject: [PATCH 143/597] #74 - Log the listening addresses at startup. --- samples/SelfHostServer/Startup.cs | 6 +++++- samples/SelfHostServer/project.json | 5 +++-- src/Microsoft.AspNet.Server.WebListener/MessagePump.cs | 4 +--- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 2 +- src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs | 5 +++-- src/Microsoft.Net.Http.Server/WebListener.cs | 7 ++++++- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index f037e486bb..ac29316bd5 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -22,17 +22,21 @@ using System.Threading; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Server.WebListener; +using Microsoft.Framework.Logging; +using Microsoft.Framework.Logging.Console; using Microsoft.Net.Http.Server; namespace SelfHostServer { public class Startup { - public void Configure(IApplicationBuilder app) + public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { var info = (ServerInformation)app.Server; info.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationTypes.AllowAnonymous; + loggerfactory.AddConsole(); + app.Run(async context => { if (context.IsWebSocketRequest) diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 5d32685c69..ffc11cd083 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,8 @@ { "dependencies": { - "Microsoft.AspNet.Http": "1.0.0-*", - "Microsoft.AspNet.Server.WebListener": "1.0.0-*" + "Microsoft.AspNet.Hosting": "1.0.0-*", + "Microsoft.AspNet.Server.WebListener": "1.0.0-*", + "Microsoft.Framework.Logging.Console": "1.0.0-*" }, "commands": { "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:8080" }, "frameworks": { diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index f376c034af..692d121eb3 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -91,8 +91,6 @@ namespace Microsoft.AspNet.Server.WebListener throw new InvalidOperationException("No address prefixes were defined."); } - LogHelper.LogInfo(_logger, "Start"); - _listener.Start(); ActivateRequestProcessingLimits(); @@ -204,11 +202,11 @@ namespace Microsoft.AspNet.Server.WebListener public void Dispose() { - LogHelper.LogInfo(_logger, "Stop"); _stopping = true; // Wait for active requests to drain if (_outstandingRequests > 0) { + LogHelper.LogInfo(_logger, "Stopping, waiting for " + _outstandingRequests + " request(s) to drain."); _shutdownSignal.WaitOne(); } // All requests are finished diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 803beae3af..f2eab5f7bc 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Server.WebListener [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] public IServerInformation Initialize(IConfiguration configuration) { - Microsoft.Net.Http.Server.WebListener listener = new Microsoft.Net.Http.Server.WebListener(); + Microsoft.Net.Http.Server.WebListener listener = new Microsoft.Net.Http.Server.WebListener(_loggerFactory); ParseAddresses(configuration, listener); return new ServerInformation(new MessagePump(listener, _loggerFactory)); } diff --git a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs index 0908630137..4e8ee48d60 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs @@ -162,9 +162,9 @@ namespace Microsoft.Net.Http.Server private void RegisterPrefix(string uriPrefix, int contextId) { - uint statusCode = 0; + LogHelper.LogInfo(_webListener.Logger, "Listening on prefix: " + uriPrefix); - statusCode = + uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup( _webListener.UrlGroupId, uriPrefix, @@ -187,6 +187,7 @@ namespace Microsoft.Net.Http.Server private bool UnregisterPrefix(string uriPrefix) { uint statusCode = 0; + LogHelper.LogInfo(_webListener.Logger, "Stop listening on prefix: " + uriPrefix); statusCode = UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup( diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 54cb36fd20..68d5b15619 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -109,6 +109,12 @@ namespace Microsoft.Net.Http.Server _connectionCancellationTokens = new ConcurrentDictionary(); } + public WebListener(ILoggerFactory factory) + : this() + { + _logger = LogHelper.CreateLogger(factory, typeof(WebListener)); + } + internal enum State { Stopped, @@ -470,7 +476,6 @@ namespace Microsoft.Net.Http.Server { return; } - LogHelper.LogInfo(_logger, "Stop"); _urlPrefixes.UnregisterAllPrefixes(); From 2ecf92f7e877235b603f369ed2e56dbde522d201 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 2 Dec 2014 10:10:41 -0800 Subject: [PATCH 144/597] #79 - Log verbose request & response details. --- samples/SelfHostServer/SelfHostServer.kproj | 13 +++- samples/SelfHostServer/Startup.cs | 2 +- samples/SelfHostServer/project.json | 1 + .../RequestProcessing/HeadersLogStructure.cs | 42 +++++++++++++ .../RequestProcessing/Request.cs | 59 +++++++++++++++++-- .../RequestProcessing/Response.cs | 52 +++++++++++++++- 6 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/HeadersLogStructure.cs diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index 2695c3ae40..003e2613c1 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -1,4 +1,4 @@ - + 14.0 @@ -7,11 +7,22 @@ 1236f93a-ac5c-4a77-9477-c88f040151ca + + ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ 2.0 + + SelfHostServer + + + 2.0 + 59517 + + web + diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index ac29316bd5..fae50ab407 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -35,7 +35,7 @@ namespace SelfHostServer var info = (ServerInformation)app.Server; info.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationTypes.AllowAnonymous; - loggerfactory.AddConsole(); + loggerfactory.AddConsole(LogLevel.Verbose); app.Run(async context => { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index ffc11cd083..aded313626 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,4 +1,5 @@ { + "webroot": "wwwroot", "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeadersLogStructure.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeadersLogStructure.cs new file mode 100644 index 0000000000..26c182df2a --- /dev/null +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeadersLogStructure.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System.Collections; + +namespace Microsoft.Net.Http.Server +{ + internal class HeadersLogStructure : IEnumerable + { + private readonly HeaderCollection _headers; + + internal HeadersLogStructure(HeaderCollection headers) + { + _headers = headers; + } + + IEnumerator IEnumerable.GetEnumerator() + { + foreach (var header in _headers) + { + foreach (var value in header.Value) + { + yield return header.Key + ": " + value; + } + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 750d4425d3..bee0c09df9 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -22,6 +22,7 @@ //------------------------------------------------------------------------------ using System; +using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -29,11 +30,10 @@ using System.Net; using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; -#if !ASPNETCORE50 -using System.Security.Principal; -#endif +using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Framework.Logging; namespace Microsoft.Net.Http.Server { @@ -72,7 +72,7 @@ namespace Microsoft.Net.Http.Server private ClaimsPrincipal _user; private bool _isDisposed = false; - + internal unsafe Request(RequestContext httpContext, NativeRequestContext memoryBlob) { // TODO: Verbose log @@ -147,7 +147,10 @@ namespace Microsoft.Net.Http.Server // TODO: Verbose log parameters - // TODO: Verbose log headers + if (_requestContext.Logger.IsEnabled(LogLevel.Verbose)) + { + RequestContext.Logger.WriteVerbose(new ReceiveRequestLogContext(this)); + } } internal SslStatus SslStatus @@ -510,5 +513,51 @@ namespace Microsoft.Net.Http.Server _nativeStream = new RequestStream(RequestContext); } } + + private class ReceiveRequestLogContext : LoggerStructureBase + { + private readonly Request _request; + + internal ReceiveRequestLogContext(Request request) + { + _request = request; + Message = "Received Request"; + } + + public string Method { get { return _request.Method; } } + public string PathBase { get { return _request.PathBase; } } + public string Path { get { return _request.Path; } } + public string Query { get { return _request.QueryString; } } + public string Protocol { get { return "HTTP/" + _request.ProtocolVersion.ToString(2); } } + public IEnumerable Headers { get { return new HeadersLogStructure(_request.Headers); } } + + public override string Format() + { + var requestBuilder = new StringBuilder("Received request: "); + + // GET /path?query HTTP/1.1 + requestBuilder.Append(Method); + requestBuilder.Append(" "); + requestBuilder.Append(PathBase); + requestBuilder.Append(Path); + requestBuilder.Append(Query); + requestBuilder.Append(" "); + requestBuilder.Append(Protocol); + requestBuilder.Append("; Headers: { "); + + foreach (var header in _request.Headers) + { + foreach (var value in header.Value) + { + requestBuilder.Append(header.Key); + requestBuilder.Append(": "); + requestBuilder.Append(value); + requestBuilder.Append("; "); + } + } + requestBuilder.Append("}"); + return requestBuilder.ToString(); + } + } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 21149425af..c1a3c7b373 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -22,14 +22,17 @@ //------------------------------------------------------------------------------ using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Framework.Logging; namespace Microsoft.Net.Http.Server { @@ -358,9 +361,13 @@ namespace Microsoft.Net.Http.Server { Debug.Assert(!HeadersSent, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); - // TODO: Verbose log headers _responseState = ResponseState.SentHeaders; - string reasonPhrase = GetReasonPhrase(_nativeResponse.Response_V1.StatusCode); + var reasonPhrase = GetReasonPhrase(StatusCode); + + if (RequestContext.Logger.IsEnabled(LogLevel.Verbose)) + { + RequestContext.Logger.WriteVerbose(new SendResponseLogContext(this)); + } /* if (m_BoundaryType==BoundaryType.Raw) { @@ -837,5 +844,46 @@ namespace Microsoft.Net.Http.Server actionPair.Item1(actionPair.Item2); } } + + private class SendResponseLogContext : LoggerStructureBase + { + private readonly Response _response; + + internal SendResponseLogContext(Response response) + { + _response = response; + Message = "Sending Response"; + } + + public string Protocol { get { return "HTTP/1.1"; } } // HTTP.SYS only allows 1.1 responses. + public string StatusCode { get { return _response.StatusCode.ToString(CultureInfo.InvariantCulture); } } + public string ReasonPhrase { get { return _response.ReasonPhrase ?? _response.GetReasonPhrase(_response.StatusCode); } } + public IEnumerable Headers { get { return new HeadersLogStructure(_response.Headers); } } + + public override string Format() + { + // HTTP/1.1 200 OK + var responseBuilder = new StringBuilder("Sending Response: "); + responseBuilder.Append(Protocol); + responseBuilder.Append(" "); + responseBuilder.Append(StatusCode); + responseBuilder.Append(" "); + responseBuilder.Append(ReasonPhrase); + responseBuilder.Append("; Headers: { "); + + foreach (var header in _response.Headers) + { + foreach (var value in header.Value) + { + responseBuilder.Append(header.Key); + responseBuilder.Append(": "); + responseBuilder.Append(value); + responseBuilder.Append("; "); + } + } + responseBuilder.Append("}"); + return responseBuilder.ToString(); + } + } } } From ce8abf776784cf6569180e99ad3241b739631c6a Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 2 Dec 2014 13:45:29 -0800 Subject: [PATCH 145/597] Ensure the logger factory is initialized. --- src/Microsoft.Net.Http.Server/LogHelper.cs | 2 +- src/Microsoft.Net.Http.Server/WebListener.cs | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index 01501b4607..b67a077da5 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -34,7 +34,7 @@ namespace Microsoft.Net.Http.Server { if (factory == null) { - return null; + factory = new LoggerFactory(); } return factory.Create(type.FullName); diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 68d5b15619..e31e158314 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -91,12 +91,19 @@ namespace Microsoft.Net.Http.Server private long? _requestQueueLength; public WebListener() + : this(new LoggerFactory()) + { + } + + public WebListener(ILoggerFactory factory) { if (!UnsafeNclNativeMethods.HttpApi.Supported) { throw new PlatformNotSupportedException(); } + _logger = LogHelper.CreateLogger(factory, typeof(WebListener)); + Debug.Assert(UnsafeNclNativeMethods.HttpApi.ApiVersion == UnsafeNclNativeMethods.HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version"); @@ -109,12 +116,6 @@ namespace Microsoft.Net.Http.Server _connectionCancellationTokens = new ConcurrentDictionary(); } - public WebListener(ILoggerFactory factory) - : this() - { - _logger = LogHelper.CreateLogger(factory, typeof(WebListener)); - } - internal enum State { Stopped, From 4585b8d7679f638312019203975d766f7f4dfce3 Mon Sep 17 00:00:00 2001 From: Suhas Joshi Date: Mon, 8 Dec 2014 15:15:59 -0800 Subject: [PATCH 146/597] Updating to release NuGet.config --- NuGet.Config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.Config b/NuGet.Config index f41e9c631d..2d3b0cb857 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@  - + From f380f6982f2e9a97bc39d5ab098e9e12236825b3 Mon Sep 17 00:00:00 2001 From: Suhas Joshi Date: Mon, 8 Dec 2014 15:25:06 -0800 Subject: [PATCH 147/597] Updating to dev NuGet.config --- NuGet.Config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.Config b/NuGet.Config index 2d3b0cb857..f41e9c631d 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@  - + From 70b2bdba9989c04592a88ab225c7e88fd8ba5af7 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 15 Dec 2014 15:07:49 -0800 Subject: [PATCH 148/597] Reacting to System.Threading version changes --- src/Microsoft.Net.WebSockets/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 318b478a14..b36dc2a234 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -19,7 +19,7 @@ "System.Runtime.Extensions": "4.0.10-beta-*", "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", "System.Text.Encoding.Extensions": "4.0.10-beta-*", - "System.Threading": "4.0.0-beta-*", + "System.Threading": "4.0.10-beta-*", "System.Threading.Overlapped": "4.0.0-beta-*", "System.Threading.Tasks": "4.0.10-beta-*", "System.Threading.Timer": "4.0.0-beta-*", From e10f64c32f0293424182d62078a4892a37c8d096 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Mon, 15 Dec 2014 16:45:35 -0800 Subject: [PATCH 149/597] Ignore some tests on downlevel --- .../OpaqueUpgradeTests.cs | 16 +++++++++++----- .../WebSocketTests.cs | 13 +++++++++---- .../project.json | 1 + 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index cfbcb1827c..e3251b226d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -26,13 +26,15 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.AspNet.Server.WebListener { public class OpaqueUpgradeTests { - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task OpaqueUpgrade_SupportKeys_Present() { string address; @@ -59,7 +61,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task OpaqueUpgrade_AfterHeadersSent_Throws() { bool? upgradeThrew = null; @@ -88,7 +91,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task OpaqueUpgrade_GetUpgrade_Success() { ManualResetEvent waitHandle = new ManualResetEvent(false); @@ -115,7 +119,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Theory] + [ConditionalTheory] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] // See HTTP_VERB for known verbs [InlineData("UNKNOWN", null)] [InlineData("INVALID", null)] @@ -173,7 +178,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Theory] + [ConditionalTheory] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] // Http.Sys returns a 411 Length Required if PUT or POST does not specify content-length or chunked. [InlineData("POST", "Content-Length: 10")] [InlineData("POST", "Transfer-Encoding: chunked")] diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index c35719bd76..ba477973da 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -24,13 +24,15 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.AspNet.Server.WebListener { public class WebSocketTests { - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task WebSocketTests_SupportKeys_Present() { string address; @@ -57,7 +59,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task WebSocketTests_AfterHeadersSent_Throws() { bool? upgradeThrew = null; @@ -86,7 +89,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task WebSocketAccept_Success() { ManualResetEvent waitHandle = new ManualResetEvent(false); @@ -112,7 +116,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task WebSocketAccept_SendAndReceive_Success() { byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index f3ed4c727f..e2fc11811b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -5,6 +5,7 @@ "dependencies": { "Microsoft.AspNet.PipelineCore": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", "Xunit.KRunner": "1.0.0-*" }, "frameworks": { From 700fa531de279c27f60cf0462cd72d7cb14ee0dc Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 15 Dec 2014 12:57:51 -0800 Subject: [PATCH 150/597] Updating tests to use official xunit --- .../project.json | 4 ++-- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index e2fc11811b..e606baf779 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,12 +1,12 @@ { "commands": { - "test": "Xunit.KRunner" + "test": "xunit.runner.kre" }, "dependencies": { "Microsoft.AspNet.PipelineCore": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", - "Xunit.KRunner": "1.0.0-*" + "xunit.runner.kre": "1.0.0-*" }, "frameworks": { "aspnet50": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 9349360b84..f9236d56fc 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,10 +1,10 @@ { "commands": { - "test": "Xunit.KRunner" + "test": "xunit.runner.kre" }, "dependencies": { "Microsoft.Net.Http.Server": "1.0.0-*", - "Xunit.KRunner": "1.0.0-*" + "xunit.runner.kre": "1.0.0-*" }, "frameworks": { "aspnet50": { From c00007caab2c99ee7b58b8ceaea51571546fe234 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Wed, 17 Dec 2014 14:08:36 -0800 Subject: [PATCH 151/597] More disabled tests --- .../OpaqueUpgradeTests.cs | 13 +++++++++---- .../WebSocketTests.cs | 10 +++++++--- .../project.json | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index d6dc580fc2..9d3d0553ec 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -6,13 +6,15 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server { public class OpaqueUpgradeTests { - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task OpaqueUpgrade_AfterHeadersSent_Throws() { string address; @@ -34,7 +36,8 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task OpaqueUpgrade_GetUpgrade_Success() { string address; @@ -55,7 +58,8 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] // See HTTP_VERB for known verbs [InlineData("UNKNOWN", null)] [InlineData("INVALID", null)] @@ -110,7 +114,8 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] // Http.Sys returns a 411 Length Required if PUT or POST does not specify content-length or chunked. [InlineData("POST", "Content-Length: 10")] [InlineData("POST", "Transfer-Encoding: chunked")] diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index 54e5a2a16c..377bb51cbd 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -6,13 +6,15 @@ using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server { public class WebSocketTests { - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task WebSocketAccept_AfterHeadersSent_Throws() { string address; @@ -33,7 +35,8 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task WebSocketAccept_Success() { string address; @@ -50,7 +53,8 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Win7And2008R2)] public async Task WebSocketAccept_SendAndReceive_Success() { string address; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index f9236d56fc..f0db29a06c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -4,6 +4,7 @@ }, "dependencies": { "Microsoft.Net.Http.Server": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", "xunit.runner.kre": "1.0.0-*" }, "frameworks": { From 8385a3c3fc70c9d20de466498310e0ce5e9051b9 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 15 Jan 2015 14:20:16 -0800 Subject: [PATCH 152/597] Handle PipelineCore rename. --- .../AuthenticationTests.cs | 2 +- .../HttpsTests.cs | 2 +- .../OpaqueUpgradeTests.cs | 2 +- .../RequestBodyTests.cs | 2 +- .../RequestHeaderTests.cs | 2 +- .../RequestTests.cs | 2 +- .../ResponseBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 2 +- .../ResponseSendFileTests.cs | 4 ++-- .../ResponseTests.cs | 2 +- .../ServerTests.cs | 2 +- .../WebSocketTests.cs | 2 +- .../project.json | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 3f40f1cbdc..6e65b638e5 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -21,7 +21,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http.Core; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 77b0523699..837751d20f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -22,8 +22,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index e3251b226d..9ce928b92c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -24,8 +24,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; using Microsoft.AspNet.Testing.xunit; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 21aa1eb02f..fefa2e0a0b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -24,7 +24,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http.Core; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index 14af34cc55..ca104ef2c8 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -21,7 +21,7 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http.Core; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 1dce566c7b..1d21766868 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -21,8 +21,8 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 11acdde941..2792b3bd35 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -23,7 +23,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http.Core; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 12cf0daf8e..a5a3467e28 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -21,8 +21,8 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index c02cd06f21..aa7e4e98f7 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -25,8 +25,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener @@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Server.WebListener private readonly string AbsoluteFilePath; private readonly string RelativeFilePath; private readonly long FileLength; - + public ResponseSendFileTests() { AbsoluteFilePath = Directory.GetFiles(Environment.CurrentDirectory).First(); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index 5505163782..f455d233bb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -20,8 +20,8 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 7e39695da9..5a85157c6b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -26,7 +26,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Http.Core; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index ba477973da..712d31b78a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -22,8 +22,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.PipelineCore; using Microsoft.AspNet.Testing.xunit; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index e606baf779..76420d3c8e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -3,7 +3,7 @@ "test": "xunit.runner.kre" }, "dependencies": { - "Microsoft.AspNet.PipelineCore": "1.0.0-*", + "Microsoft.AspNet.Http.Core": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", "xunit.runner.kre": "1.0.0-*" From 65adcffb924013120443dc325bac06763167b729 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Sun, 18 Jan 2015 20:59:49 -0800 Subject: [PATCH 153/597] Handle HttpFeature rename --- .../AuthenticationHandler.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 4 ++-- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- .../HttpsTests.cs | 2 +- .../OpaqueUpgradeTests.cs | 2 +- .../RequestTests.cs | 2 +- .../ResponseHeaderTests.cs | 2 +- .../ResponseSendFileTests.cs | 2 +- .../ResponseTests.cs | 2 +- .../WebSocketTests.cs | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index 272134c0fe..d565b3f401 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -26,7 +26,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.HttpFeature.Security; +using Microsoft.AspNet.Http.Interfaces.Security; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index af21159d7e..ae7c7a482f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -26,8 +26,8 @@ using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.HttpFeature; -using Microsoft.AspNet.HttpFeature.Security; +using Microsoft.AspNet.Http.Interfaces; +using Microsoft.AspNet.Http.Interfaces.Security; using Microsoft.Net.Http.Server; using Microsoft.Net.WebSockets; diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index ab5ef64d0d..f1ecf9bd6f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -4,7 +4,7 @@ "dependencies": { "Microsoft.AspNet.FeatureModel": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", - "Microsoft.AspNet.HttpFeature": { "version": "1.0.0-*", "type": "build" }, + "Microsoft.AspNet.Http.Interfaces": { "version": "1.0.0-*", "type": "build" }, "Microsoft.Framework.ConfigurationModel": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 837751d20f..8b8f4e5c35 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -23,7 +23,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 9ce928b92c..134ec54729 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -25,7 +25,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; using Microsoft.AspNet.Testing.xunit; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 1d21766868..3730f1ec1e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -22,7 +22,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index a5a3467e28..987b767bb6 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -22,7 +22,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index aa7e4e98f7..8052698f5b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -26,7 +26,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index f455d233bb..055f3f606d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -21,7 +21,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index 712d31b78a..777fe69607 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -23,7 +23,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.Http.Interfaces; using Microsoft.AspNet.Testing.xunit; using Xunit; From b6595e9ba2e2367b6d12dbfbf93a51b67a78b6dc Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 20 Jan 2015 01:37:09 -0800 Subject: [PATCH 154/597] Updating build.cmd and build.sh to use dotnetsdk --- build.cmd | 6 +++--- build.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.cmd b/build.cmd index 86ca5bbbf1..c8041fdd9d 100644 --- a/build.cmd +++ b/build.cmd @@ -20,9 +20,9 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion IF "%SKIP_KRE_INSTALL%"=="1" goto run -CALL packages\KoreBuild\build\kvm upgrade -runtime CLR -x86 -CALL packages\KoreBuild\build\kvm install default -runtime CoreCLR -x86 +CALL packages\KoreBuild\build\dotnetsdk upgrade -runtime CLR -x86 +CALL packages\KoreBuild\build\dotnetsdk install default -runtime CoreCLR -x86 :run -CALL packages\KoreBuild\build\kvm use default -runtime CLR -x86 +CALL packages\KoreBuild\build\dotnetsdk use default -runtime CLR -x86 packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh index c7873ef58e..350d7e389a 100644 --- a/build.sh +++ b/build.sh @@ -28,11 +28,11 @@ if test ! -d packages/KoreBuild; then fi if ! type k > /dev/null 2>&1; then - source packages/KoreBuild/build/kvm.sh + source packages/KoreBuild/build/dotnetsdk.sh fi if ! type k > /dev/null 2>&1; then - kvm upgrade + dotnetsdk upgrade fi mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" From 66611292cf91f148d06efc40263a8fa96667a053 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 20 Jan 2015 18:41:06 -0800 Subject: [PATCH 155/597] Rename SKIP_KRE_INSTALL to SKIP_DOTNET_INSTALL --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index c8041fdd9d..220a1ff561 100644 --- a/build.cmd +++ b/build.cmd @@ -19,7 +19,7 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion -IF "%SKIP_KRE_INSTALL%"=="1" goto run +IF "%SKIP_DOTNET_INSTALL%"=="1" goto run CALL packages\KoreBuild\build\dotnetsdk upgrade -runtime CLR -x86 CALL packages\KoreBuild\build\dotnetsdk install default -runtime CoreCLR -x86 From 0ebd307a0f481d21c922cda7a56197bfe4045151 Mon Sep 17 00:00:00 2001 From: Suhas Joshi Date: Wed, 21 Jan 2015 15:55:20 -0800 Subject: [PATCH 156/597] Updating to release NuGet.config --- NuGet.Config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.Config b/NuGet.Config index f41e9c631d..2d3b0cb857 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@  - + From d71a92393c7dd9ebe39546046d59745c24e09cdd Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 22 Jan 2015 17:18:49 -0800 Subject: [PATCH 157/597] React to kpm renaming --- samples/HotAddSample/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 54bd01b3f5..ab2ef37210 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -4,7 +4,7 @@ "exclude": [ "wwwroot" ], - "packExclude": [ + "bundleExclude": [ "**.kproj", "**.user", "**.vspscc" From 45ebae0ec80a4bbc8e7d45e8c52cbe5f77048a4f Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 28 Jan 2015 18:48:41 -0800 Subject: [PATCH 158/597] Update build.cmd and build.sh to use kvm --- build.cmd | 6 +++--- build.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.cmd b/build.cmd index 220a1ff561..5885abe388 100644 --- a/build.cmd +++ b/build.cmd @@ -20,9 +20,9 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion IF "%SKIP_DOTNET_INSTALL%"=="1" goto run -CALL packages\KoreBuild\build\dotnetsdk upgrade -runtime CLR -x86 -CALL packages\KoreBuild\build\dotnetsdk install default -runtime CoreCLR -x86 +CALL packages\KoreBuild\build\kvm upgrade -runtime CLR -x86 +CALL packages\KoreBuild\build\kvm install default -runtime CoreCLR -x86 :run -CALL packages\KoreBuild\build\dotnetsdk use default -runtime CLR -x86 +CALL packages\KoreBuild\build\kvm use default -runtime CLR -x86 packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh index 350d7e389a..c7873ef58e 100644 --- a/build.sh +++ b/build.sh @@ -28,11 +28,11 @@ if test ! -d packages/KoreBuild; then fi if ! type k > /dev/null 2>&1; then - source packages/KoreBuild/build/dotnetsdk.sh + source packages/KoreBuild/build/kvm.sh fi if ! type k > /dev/null 2>&1; then - dotnetsdk upgrade + kvm upgrade fi mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" From 8621da6cac590578bc74008b196e9eb8d6faa18b Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 28 Jan 2015 18:48:55 -0800 Subject: [PATCH 159/597] Change SKIP_DOTNET_INSTALL to SKIP_KRE_INSTALL --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index 5885abe388..86ca5bbbf1 100644 --- a/build.cmd +++ b/build.cmd @@ -19,7 +19,7 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion -IF "%SKIP_DOTNET_INSTALL%"=="1" goto run +IF "%SKIP_KRE_INSTALL%"=="1" goto run CALL packages\KoreBuild\build\kvm upgrade -runtime CLR -x86 CALL packages\KoreBuild\build\kvm install default -runtime CoreCLR -x86 From 4a0518ec99b9a353e5b175d1c3b6216469d8465c Mon Sep 17 00:00:00 2001 From: Brennan Date: Wed, 4 Feb 2015 14:29:14 -0800 Subject: [PATCH 160/597] Updating .kproj file --- samples/SelfHostServer/SelfHostServer.kproj | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.kproj index 003e2613c1..e67781baec 100644 --- a/samples/SelfHostServer/SelfHostServer.kproj +++ b/samples/SelfHostServer/SelfHostServer.kproj @@ -7,22 +7,12 @@ 1236f93a-ac5c-4a77-9477-c88f040151ca - - ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ - - 2.0 - - - SelfHostServer - 2.0 59517 - - web From f6e049ff85515f8337070a0ab7bdceb35c393774 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Tue, 10 Feb 2015 10:27:41 -0800 Subject: [PATCH 161/597] Removed the build time dependency and added a reference to Hosting.Interfaces --- .../IServerFactory.cs | 32 ------------------- .../project.json | 6 ++-- 2 files changed, 3 insertions(+), 35 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/IServerFactory.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/IServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/IServerFactory.cs deleted file mode 100644 index 0b75dbe5e9..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/IServerFactory.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -using System; -using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.Framework.ConfigurationModel; -using Microsoft.Framework.Runtime; - -namespace Microsoft.AspNet.Hosting.Server -{ - [AssemblyNeutral] - public interface IServerFactory - { - IServerInformation Initialize(IConfiguration configuration); - IDisposable Start(IServerInformation serverInformation, Func application); - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index f1ecf9bd6f..e1ae35960c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -4,7 +4,8 @@ "dependencies": { "Microsoft.AspNet.FeatureModel": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", - "Microsoft.AspNet.Http.Interfaces": { "version": "1.0.0-*", "type": "build" }, + "Microsoft.AspNet.Http.Interfaces": "1.0.0-*", + "Microsoft.AspNet.Hosting.Interfaces": "1.0.0-*", "Microsoft.Framework.ConfigurationModel": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*", @@ -15,7 +16,6 @@ }, "frameworks": { "aspnet50": { }, - "aspnetcore50": { - } + "aspnetcore50": { } } } From 9511a7a7189bf0a6abda23aae05bc6004161ef66 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Mon, 16 Feb 2015 14:16:16 -0800 Subject: [PATCH 162/597] Add project.lock.json to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 08e21e25bf..ac82da7568 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ nuget.exe *.ncrunchsolution *.*sdf *.ipch -*.sln.ide \ No newline at end of file +*.sln.ide +project.lock.json From fc6b855f422a8039e39d757e66429fa6845f281e Mon Sep 17 00:00:00 2001 From: Praburaj Date: Wed, 25 Feb 2015 17:43:04 -0800 Subject: [PATCH 163/597] Changing the AppFunc signature to pass IFeatureCollection Reaction to bug: https://github.com/aspnet/Hosting/issues/162 --- src/Microsoft.AspNet.Server.WebListener/MessagePump.cs | 3 ++- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index 692d121eb3..a43d893307 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -19,12 +19,13 @@ using System; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; using Microsoft.Framework.Logging; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; + using AppFunc = Func; internal class MessagePump : IDisposable { diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index f2eab5f7bc..0ee2f188c9 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -35,11 +35,10 @@ // limitations under the License. using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Hosting.Server; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.Logging; @@ -47,7 +46,7 @@ using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; + using AppFunc = Func; /// /// Implements the setup process for this server. From c08721c7b39c976bb205468dcbd7fc15151d5077 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 2 Mar 2015 15:37:35 -0800 Subject: [PATCH 164/597] React to AuthN renames --- samples/SelfHostServer/Startup.cs | 2 +- .../AuthenticationHandler.cs | 68 +++--- .../FeatureContext.cs | 2 +- .../AuthenticationManager.cs | 47 ++-- ...ationTypes.cs => AuthenticationSchemes.cs} | 3 +- .../RequestProcessing/RequestContext.cs | 6 +- src/Microsoft.Net.Http.Server/WebListener.cs | 2 +- .../AuthenticationTests.cs | 221 +++++++++--------- .../Utilities.cs | 10 +- .../AuthenticationTests.cs | 90 +++---- .../Utilities.cs | 4 +- 11 files changed, 228 insertions(+), 227 deletions(-) rename src/Microsoft.Net.Http.Server/{AuthenticationTypes.cs => AuthenticationSchemes.cs} (89%) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index fae50ab407..1597e5628b 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -33,7 +33,7 @@ namespace SelfHostServer public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { var info = (ServerInformation)app.Server; - info.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationTypes.AllowAnonymous; + info.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; loggerfactory.AddConsole(LogLevel.Verbose); diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index d565b3f401..7d2f8cd4e5 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -26,7 +26,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Interfaces.Security; +using Microsoft.AspNet.Http.Interfaces.Authentication; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener @@ -34,14 +34,14 @@ namespace Microsoft.AspNet.Server.WebListener internal class AuthenticationHandler : IAuthenticationHandler { private RequestContext _requestContext; - private AuthenticationTypes _authTypes; - private AuthenticationTypes _customChallenges; + private AuthenticationSchemes _authSchemes; + private AuthenticationSchemes _customChallenges; internal AuthenticationHandler(RequestContext requestContext) { _requestContext = requestContext; - _authTypes = requestContext.AuthenticationChallenges; - _customChallenges = AuthenticationTypes.None; + _authSchemes = requestContext.AuthenticationChallenges; + _customChallenges = AuthenticationSchemes.None; } public void Authenticate(IAuthenticateContext context) @@ -49,19 +49,19 @@ namespace Microsoft.AspNet.Server.WebListener var user = _requestContext.User; var identity = user == null ? null : (ClaimsIdentity)user.Identity; - foreach (var authType in ListEnabledAuthTypes()) + foreach (var authType in ListEnabledAuthSchemes()) { - string authString = authType.ToString(); - if (context.AuthenticationTypes.Contains(authString, StringComparer.Ordinal)) + string authScheme = authType.ToString(); + if (context.AuthenticationSchemes.Contains(authScheme, StringComparer.Ordinal)) { if (identity != null && identity.IsAuthenticated - && string.Equals(authString, identity.AuthenticationType, StringComparison.Ordinal)) + && string.Equals(authScheme, identity.AuthenticationType, StringComparison.Ordinal)) { - context.Authenticated((ClaimsIdentity)user.Identity, properties: null, description: GetDescription(user.Identity.AuthenticationType)); + context.Authenticated(new ClaimsPrincipal(user.Identity), properties: null, description: GetDescription(authScheme)); } else { - context.NotAuthenticated(authString, properties: null, description: GetDescription(user.Identity.AuthenticationType)); + context.NotAuthenticated(authScheme, properties: null, description: GetDescription(authScheme)); } } } @@ -75,27 +75,27 @@ namespace Microsoft.AspNet.Server.WebListener public void Challenge(IChallengeContext context) { - foreach (var authType in ListEnabledAuthTypes()) + foreach (var scheme in ListEnabledAuthSchemes()) { - var authString = authType.ToString(); + var authScheme = scheme.ToString(); // Not including any auth types means it's a blanket challenge for any auth type. - if (context.AuthenticationTypes == null || !context.AuthenticationTypes.Any() - || context.AuthenticationTypes.Contains(authString, StringComparer.Ordinal)) + if (context.AuthenticationSchemes == null || !context.AuthenticationSchemes.Any() + || context.AuthenticationSchemes.Contains(authScheme, StringComparer.Ordinal)) { - _customChallenges |= authType; - context.Accept(authString, GetDescription(authType.ToString())); + _customChallenges |= scheme; + context.Accept(authScheme, GetDescription(authScheme)); } } // A challenge was issued, it overrides any pre-set auth types. _requestContext.AuthenticationChallenges = _customChallenges; } - public void GetDescriptions(IAuthTypeContext context) + public void GetDescriptions(IDescribeSchemesContext context) { // TODO: Caching, this data doesn't change per request. - foreach (var authType in ListEnabledAuthTypes()) + foreach (var scheme in ListEnabledAuthSchemes()) { - context.Accept(GetDescription(authType.ToString())); + context.Accept(GetDescription(scheme.ToString())); } } @@ -109,39 +109,39 @@ namespace Microsoft.AspNet.Server.WebListener // Not supported } - private IDictionary GetDescription(string authenticationType) + private IDictionary GetDescription(string authenticationScheme) { return new Dictionary() { - { "AuthenticationType", authenticationType }, - { "Caption", "Windows:" + authenticationType }, + { "AuthenticationScheme", authenticationScheme }, + { "Caption", "Windows:" + authenticationScheme }, }; } - private IEnumerable ListEnabledAuthTypes() + private IEnumerable ListEnabledAuthSchemes() { // Order by strength. - if ((_authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos) + if ((_authSchemes & AuthenticationSchemes.Kerberos) == AuthenticationSchemes.Kerberos) { - yield return AuthenticationTypes.Kerberos; + yield return AuthenticationSchemes.Kerberos; } - if ((_authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate) + if ((_authSchemes & AuthenticationSchemes.Negotiate) == AuthenticationSchemes.Negotiate) { - yield return AuthenticationTypes.Negotiate; + yield return AuthenticationSchemes.Negotiate; } - if ((_authTypes & AuthenticationTypes.NTLM) == AuthenticationTypes.NTLM) + if ((_authSchemes & AuthenticationSchemes.NTLM) == AuthenticationSchemes.NTLM) { - yield return AuthenticationTypes.NTLM; + yield return AuthenticationSchemes.NTLM; } - /*if ((_authTypes & AuthenticationTypes.Digest) == AuthenticationTypes.Digest) + /*if ((_authSchemes & AuthenticationSchemes.Digest) == AuthenticationSchemes.Digest) { // TODO: throw new NotImplementedException("Digest challenge generation has not been implemented."); - yield return AuthenticationTypes.Digest; + yield return AuthenticationSchemes.Digest; }*/ - if ((_authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic) + if ((_authSchemes & AuthenticationSchemes.Basic) == AuthenticationSchemes.Basic) { - yield return AuthenticationTypes.Basic; + yield return AuthenticationSchemes.Basic; } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index ae7c7a482f..8a2e919c6a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -27,7 +27,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Interfaces; -using Microsoft.AspNet.Http.Interfaces.Security; +using Microsoft.AspNet.Http.Interfaces.Authentication; using Microsoft.Net.Http.Server; using Microsoft.Net.WebSockets; diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 9be0a01897..adb806c0af 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -23,7 +23,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Security.Claims; @@ -48,29 +47,29 @@ namespace Microsoft.Net.Http.Server #endif private WebListener _server; - private AuthenticationTypes _authTypes; + private AuthenticationSchemes _authSchemes; internal AuthenticationManager(WebListener listener) { _server = listener; - _authTypes = AuthenticationTypes.AllowAnonymous; + _authSchemes = AuthenticationSchemes.AllowAnonymous; } #region Properties - public AuthenticationTypes AuthenticationTypes + public AuthenticationSchemes AuthenticationSchemes { get { - return _authTypes; + return _authSchemes; } set { - if (_authTypes == AuthenticationTypes.None) + if (_authSchemes == AuthenticationSchemes.None) { throw new ArgumentException("value", "'None' is not a valid authentication type. Use 'AllowAnonymous' instead."); } - _authTypes = value; + _authSchemes = value; SetServerSecurity(); } } @@ -79,7 +78,7 @@ namespace Microsoft.Net.Http.Server { get { - return ((_authTypes & AuthenticationTypes.AllowAnonymous) == AuthenticationTypes.AllowAnonymous); + return ((_authSchemes & AuthenticationSchemes.AllowAnonymous) == AuthenticationSchemes.AllowAnonymous); } } @@ -91,10 +90,10 @@ namespace Microsoft.Net.Http.Server new UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO(); authInfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; - var authTypes = (UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES)(_authTypes & ~AuthenticationTypes.AllowAnonymous); - if (authTypes != UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES.NONE) + var authSchemes = (UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES)(_authSchemes & ~AuthenticationSchemes.AllowAnonymous); + if (authSchemes != UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES.NONE) { - authInfo.AuthSchemes = authTypes; + authInfo.AuthSchemes = authSchemes; // TODO: // NTLM auth sharing (on by default?) DisableNTLMCredentialCaching @@ -111,35 +110,35 @@ namespace Microsoft.Net.Http.Server } } - internal static IList GenerateChallenges(AuthenticationTypes authTypes) + internal static IList GenerateChallenges(AuthenticationSchemes authSchemes) { IList challenges = new List(); - if (authTypes == AuthenticationTypes.None) + if (authSchemes == AuthenticationSchemes.None) { return challenges; } // Order by strength. - if ((authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos) + if ((authSchemes & AuthenticationSchemes.Kerberos) == AuthenticationSchemes.Kerberos) { challenges.Add("Kerberos"); } - if ((authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate) + if ((authSchemes & AuthenticationSchemes.Negotiate) == AuthenticationSchemes.Negotiate) { challenges.Add("Negotiate"); } - if ((authTypes & AuthenticationTypes.NTLM) == AuthenticationTypes.NTLM) + if ((authSchemes & AuthenticationSchemes.NTLM) == AuthenticationSchemes.NTLM) { challenges.Add("NTLM"); } - /*if ((_authTypes & AuthenticationTypes.Digest) == AuthenticationTypes.Digest) + /*if ((_authSchemes & AuthenticationSchemes.Digest) == AuthenticationSchemes.Digest) { // TODO: throw new NotImplementedException("Digest challenge generation has not been implemented."); // challenges.Add("Digest"); }*/ - if ((authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic) + if ((authSchemes & AuthenticationSchemes.Basic) == AuthenticationSchemes.Basic) { // TODO: Realm challenges.Add("Basic"); @@ -180,20 +179,20 @@ namespace Microsoft.Net.Http.Server return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated } - private static AuthenticationTypes GetAuthTypeFromRequest(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE input) + private static AuthenticationSchemes GetAuthTypeFromRequest(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE input) { switch (input) { case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic: - return AuthenticationTypes.Basic; + return AuthenticationSchemes.Basic; // case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest: - // return AuthenticationTypes.Digest; + // return AuthenticationSchemes.Digest; case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM: - return AuthenticationTypes.NTLM; + return AuthenticationSchemes.NTLM; case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate: - return AuthenticationTypes.Negotiate; + return AuthenticationSchemes.Negotiate; case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos: - return AuthenticationTypes.Kerberos; + return AuthenticationSchemes.Kerberos; default: throw new NotImplementedException(input.ToString()); } diff --git a/src/Microsoft.Net.Http.Server/AuthenticationTypes.cs b/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs similarity index 89% rename from src/Microsoft.Net.Http.Server/AuthenticationTypes.cs rename to src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs index a7c39ab7c2..d8ee617c16 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationTypes.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs @@ -19,8 +19,9 @@ using System; namespace Microsoft.Net.Http.Server { + // REVIEW: this appears to be very similar to System.Net.AuthenticationSchemes [Flags] - public enum AuthenticationTypes + public enum AuthenticationSchemes { None = 0x0, Basic = 0x1, diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 37862cc392..4a5d7058a4 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -55,7 +55,7 @@ namespace Microsoft.Net.Http.Server _request = new Request(this, _memoryBlob); _response = new Response(this); _request.ReleasePins(); - AuthenticationChallenges = server.AuthenticationManager.AuthenticationTypes & ~AuthenticationTypes.AllowAnonymous; + AuthenticationChallenges = server.AuthenticationManager.AuthenticationSchemes & ~AuthenticationSchemes.AllowAnonymous; } public Request Request @@ -134,9 +134,9 @@ namespace Microsoft.Net.Http.Server /// /// The authentication challengest that will be added to the response if the status code is 401. - /// This must be a subset of the AuthenticationTypes enabled on the server. + /// This must be a subset of the AuthenticationSchemes enabled on the server. /// - public AuthenticationTypes AuthenticationChallenges { get; set; } + public AuthenticationSchemes AuthenticationChallenges { get; set; } public bool IsUpgradableRequest { diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index e31e158314..3185a414db 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -592,7 +592,7 @@ namespace Microsoft.Net.Http.Server if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) { SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, - AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationTypes)); + AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationSchemes)); return false; } return true; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 6e65b638e5..e96b810101 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -24,23 +24,24 @@ using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Core; using Microsoft.Net.Http.Server; using Xunit; +using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes; namespace Microsoft.AspNet.Server.WebListener { public class AuthenticationTests { [Theory] - [InlineData(AuthenticationTypes.AllowAnonymous)] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - [InlineData(AuthenticationTypes.Basic)] - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.AllowAnonymous)] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -55,12 +56,12 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented - [InlineData(AuthenticationTypes.Basic)] - public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented + [InlineData(AuthenticationSchemes.Basic)] + public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; using (Utilities.CreateHttpAuthServer(authType, out address, env => @@ -75,15 +76,15 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented - [InlineData(AuthenticationTypes.Basic)] - public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented + [InlineData(AuthenticationSchemes.Basic)] + public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -103,12 +104,12 @@ namespace Microsoft.AspNet.Server.WebListener { string address; using (Utilities.CreateHttpAuthServer( - AuthenticationTypes.Kerberos - | AuthenticationTypes.Negotiate - | AuthenticationTypes.NTLM - /* | AuthenticationTypes.Digest TODO: Not implemented */ - | AuthenticationTypes.Basic - | AuthenticationTypes.AllowAnonymous, + AuthenticationSchemes.Kerberos + | AuthenticationSchemes.Negotiate + | AuthenticationSchemes.NTLM + /* | AuthenticationSchemes.Digest TODO: Not implemented */ + | AuthenticationSchemes.Basic + | AuthenticationSchemes.AllowAnonymous, out address, env => { @@ -126,17 +127,17 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented - // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType) { string address; int requestId = 0; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -163,13 +164,13 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented - // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) { string address; using (Utilities.CreateHttpAuthServer(authType, out address, env => @@ -186,21 +187,21 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.AllowAnonymous)] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - [InlineData(AuthenticationTypes.Basic)] - // [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_GetSingleDescriptions(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.AllowAnonymous)] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + // [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_GetSingleDescriptions(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); - var resultList = context.GetAuthenticationTypes(); - if (authType == AuthenticationTypes.AllowAnonymous) + var resultList = context.GetAuthenticationSchemes(); + if (authType == AuthenticationSchemes.AllowAnonymous) { Assert.Equal(0, resultList.Count()); } @@ -208,7 +209,7 @@ namespace Microsoft.AspNet.Server.WebListener { Assert.Equal(1, resultList.Count()); var result = resultList.First(); - Assert.Equal(authType.ToString(), result.AuthenticationType); + Assert.Equal(authType.ToString(), result.AuthenticationScheme); Assert.Equal("Windows:" + authType.ToString(), result.Caption); } @@ -225,16 +226,16 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_GetMultipleDescriptions() { string address; - AuthenticationTypes authType = - AuthenticationTypes.Kerberos - | AuthenticationTypes.Negotiate - | AuthenticationTypes.NTLM - | /*AuthenticationTypes.Digest - |*/ AuthenticationTypes.Basic; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => + AuthenticationSchemes authType = + AuthenticationSchemes.Kerberos + | AuthenticationSchemes.Negotiate + | AuthenticationSchemes.NTLM + | /*AuthenticationSchemes.Digest + |*/ AuthenticationSchemes.Basic; + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); - var resultList = context.GetAuthenticationTypes(); + var resultList = context.GetAuthenticationSchemes(); Assert.Equal(4, resultList.Count()); return Task.FromResult(0); })) @@ -246,17 +247,17 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - [InlineData(AuthenticationTypes.Basic)] - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationSchemes authType) { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -273,13 +274,13 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationSchemes authType) { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); @@ -299,17 +300,17 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - [InlineData(AuthenticationTypes.Basic)] - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -325,17 +326,17 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - [InlineData(AuthenticationTypes.Basic)] - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -351,16 +352,16 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - [InlineData(AuthenticationTypes.Basic)] - public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationSchemes authType) { string address; - var authTypes = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic; - using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, out address, env => + var authTypes = AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; + using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -377,18 +378,18 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - [InlineData(AuthenticationTypes.Basic)] - public async Task AuthTypes_ChallengeDisabledAuthType_Error(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + public async Task AuthTypes_ChallengeDisabledAuthType_Error(AuthenticationSchemes authType) { string address; - var authTypes = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic; + var authTypes = AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; authTypes = authTypes & ~authType; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index 5315a6952f..5e70a77b50 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -33,22 +33,22 @@ namespace Microsoft.AspNet.Server.WebListener internal static IDisposable CreateHttpServer(out string baseAddress, AppFunc app) { string root; - return CreateDynamicHttpServer(string.Empty, AuthenticationTypes.AllowAnonymous, out root, out baseAddress, app); + return CreateDynamicHttpServer(string.Empty, AuthenticationSchemes.AllowAnonymous, out root, out baseAddress, app); } internal static IDisposable CreateHttpServerReturnRoot(string path, out string root, AppFunc app) { string baseAddress; - return CreateDynamicHttpServer(path, AuthenticationTypes.AllowAnonymous, out root, out baseAddress, app); + return CreateDynamicHttpServer(path, AuthenticationSchemes.AllowAnonymous, out root, out baseAddress, app); } - internal static IDisposable CreateHttpAuthServer(AuthenticationTypes authType, out string baseAddress, AppFunc app) + internal static IDisposable CreateHttpAuthServer(AuthenticationSchemes authType, out string baseAddress, AppFunc app) { string root; return CreateDynamicHttpServer(string.Empty, authType, out root, out baseAddress, app); } - internal static IDisposable CreateDynamicHttpServer(string basePath, AuthenticationTypes authType, out string root, out string baseAddress, AppFunc app) + internal static IDisposable CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, out string root, out string baseAddress, AppFunc app) { var factory = new ServerFactory(loggerFactory: null); lock (PortLock) @@ -63,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener var serverInfo = (ServerInformation)factory.Initialize(configuration: null); serverInfo.Listener.UrlPrefixes.Add(prefix); - serverInfo.Listener.AuthenticationManager.AuthenticationTypes = authType; + serverInfo.Listener.AuthenticationManager.AuthenticationSchemes = authType; try { return factory.Start(serverInfo, app); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 09f501fa24..f9e9316dc8 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -11,26 +11,26 @@ namespace Microsoft.Net.Http.Server public class AuthenticationTests { [Theory] - [InlineData(AuthenticationTypes.AllowAnonymous)] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] - [InlineData(AuthenticationTypes.Basic)] - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.AllowAnonymous)] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) { string address; - using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address)) { Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - if (authType == AuthenticationTypes.AllowAnonymous) + if (authType == AuthenticationSchemes.AllowAnonymous) { - Assert.Equal(AuthenticationTypes.None, context.AuthenticationChallenges); + Assert.Equal(AuthenticationSchemes.None, context.AuthenticationChallenges); } else { @@ -45,12 +45,12 @@ namespace Microsoft.Net.Http.Server } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented - [InlineData(AuthenticationTypes.Basic)] - public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Basic)] + public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; using (var server = Utilities.CreateHttpAuthServer(authType, out address)) @@ -66,15 +66,15 @@ namespace Microsoft.Net.Http.Server } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented - [InlineData(AuthenticationTypes.Basic)] - public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented + [InlineData(AuthenticationSchemes.Basic)] + public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; - using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address)) { Task responseTask = SendRequestAsync(address); @@ -95,13 +95,13 @@ namespace Microsoft.Net.Http.Server public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; - AuthenticationTypes authType = - AuthenticationTypes.Kerberos - | AuthenticationTypes.Negotiate - | AuthenticationTypes.NTLM - /* | AuthenticationTypes.Digest TODO: Not implemented */ - | AuthenticationTypes.Basic; - using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address)) + AuthenticationSchemes authType = + AuthenticationSchemes.Kerberos + | AuthenticationSchemes.Negotiate + | AuthenticationSchemes.NTLM + /* | AuthenticationSchemes.Digest TODO: Not implemented */ + | AuthenticationSchemes.Basic; + using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address)) { Task responseTask = SendRequestAsync(address); @@ -119,16 +119,16 @@ namespace Microsoft.Net.Http.Server } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented - // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType) { string address; - using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationTypes.AllowAnonymous, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address)) { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); @@ -151,13 +151,13 @@ namespace Microsoft.Net.Http.Server } [Theory] - [InlineData(AuthenticationTypes.Kerberos)] - [InlineData(AuthenticationTypes.Negotiate)] - [InlineData(AuthenticationTypes.NTLM)] - // [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented - // [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)] - public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType) + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented + // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds + [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationSchemes.Basic)] + public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) { string address; using (var server = Utilities.CreateHttpAuthServer(authType, out address)) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs index 8e8fdf16d7..fd732e11a4 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs @@ -11,10 +11,10 @@ namespace Microsoft.Net.Http.Server private static int NextPort = BasePort; private static object PortLock = new object(); - internal static WebListener CreateHttpAuthServer(AuthenticationTypes authType, out string baseAddress) + internal static WebListener CreateHttpAuthServer(AuthenticationSchemes authScheme, out string baseAddress) { var listener = CreateHttpServer(out baseAddress); - listener.AuthenticationManager.AuthenticationTypes = authType; + listener.AuthenticationManager.AuthenticationSchemes = authScheme; return listener; } From ca3259f7034f459cc683a9f2d888105429f3a1b6 Mon Sep 17 00:00:00 2001 From: Praburaj Date: Mon, 2 Mar 2015 16:52:56 -0800 Subject: [PATCH 165/597] Implementing IRequestIdentifierFeature Using code from HttpListener codebase to generate trace ids just to be consistent with other code. --- .../FeatureContext.cs | 14 ++++++++++++-- .../RequestProcessing/RequestContext.cs | 13 +++++++++++++ .../RequestTests.cs | 15 +++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 8a2e919c6a..2d1e40c6b5 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -22,7 +22,6 @@ using System.Net; using System.Net.WebSockets; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; -using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; @@ -42,7 +41,8 @@ namespace Microsoft.AspNet.Server.WebListener IHttpRequestLifetimeFeature, IHttpWebSocketFeature, IHttpAuthenticationFeature, - IHttpUpgradeFeature + IHttpUpgradeFeature, + IRequestIdentifierFeature { private RequestContext _requestContext; private FeatureCollection _features; @@ -110,6 +110,8 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpWebSocketFeature), this); } + _features.Add(typeof(IRequestIdentifierFeature), this); + // TODO: /* Server @@ -432,5 +434,13 @@ namespace Microsoft.AspNet.Server.WebListener get { return _authHandler; } set { _authHandler = value; } } + + Guid IRequestIdentifierFeature.TraceIdentifier + { + get + { + return _requestContext.TraceIdentifier; + } + } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 4a5d7058a4..b2232554ca 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -132,6 +132,19 @@ namespace Microsoft.Net.Http.Server } } + public unsafe Guid TraceIdentifier + { + get + { + // This is the base GUID used by HTTP.SYS for generating the activity ID. + // HTTP.SYS overwrites the first 8 bytes of the base GUID with RequestId to generate ETW activity ID. + + var guid = new Guid(0xffcb4c93, 0xa57f, 0x453c, 0xb6, 0x3f, 0x84, 0x71, 0xc, 0x79, 0x67, 0xbb); + *((ulong*)&guid) = Request.RequestId; + return guid; + } + } + /// /// The authentication challengest that will be added to the response if the status code is 401. /// This must be a subset of the AuthenticationSchemes enabled on the server. diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 3730f1ec1e..47bbb4d63d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -63,6 +63,11 @@ namespace Microsoft.AspNet.Server.WebListener Assert.NotEqual(0, connectionInfo.LocalPort); Assert.True(connectionInfo.IsLocal); + // Trace identifier + var requestIdentifierFeature = httpContext.GetFeature(); + Assert.NotNull(requestIdentifierFeature); + Assert.NotNull(requestIdentifierFeature.TraceIdentifier); + // Note: Response keys are validated in the ResponseTests } catch (Exception ex) @@ -95,12 +100,17 @@ namespace Microsoft.AspNet.Server.WebListener { var requestInfo = httpContext.GetFeature(); var connectionInfo = httpContext.GetFeature(); + var requestIdentifierFeature = httpContext.GetFeature(); // Request Keys Assert.Equal("http", requestInfo.Scheme); Assert.Equal(expectedPath, requestInfo.Path); Assert.Equal(expectedPathBase, requestInfo.PathBase); Assert.Equal(string.Empty, requestInfo.QueryString); + + // Trace identifier + Assert.NotNull(requestIdentifierFeature); + Assert.NotNull(requestIdentifierFeature.TraceIdentifier); } catch (Exception ex) { @@ -135,10 +145,15 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var requestInfo = httpContext.GetFeature(); + var requestIdentifierFeature = httpContext.GetFeature(); try { Assert.Equal(expectedPath, requestInfo.Path); Assert.Equal(expectedPathBase, requestInfo.PathBase); + + // Trace identifier + Assert.NotNull(requestIdentifierFeature); + Assert.NotNull(requestIdentifierFeature.TraceIdentifier); } catch (Exception ex) { From cdf6350b930d79fe62695c33236b529004571294 Mon Sep 17 00:00:00 2001 From: Brennan Date: Wed, 4 Mar 2015 17:14:23 -0800 Subject: [PATCH 166/597] Logging API changes --- src/Microsoft.AspNet.Server.WebListener/LogHelper.cs | 10 +++++----- src/Microsoft.Net.Http.Server/LogHelper.cs | 10 +++++----- .../RequestProcessing/Request.cs | 5 ++--- .../RequestProcessing/Response.cs | 5 ++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs index 2501c20620..c742caa87d 100644 --- a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -37,7 +37,7 @@ namespace Microsoft.AspNet.Server.WebListener return null; } - return factory.Create(type.FullName); + return factory.CreateLogger(type.FullName); } internal static void LogInfo(ILogger logger, string data) @@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger.WriteInformation(data); + logger.LogInformation(data); } } @@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger.WriteVerbose(data); + logger.LogVerbose(data); } } @@ -77,7 +77,7 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger.WriteError(location, exception); + logger.LogError(location, exception); } } @@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger.WriteError(location + "; " + message); + logger.LogError(location + "; " + message); } } } diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index b67a077da5..7413e56a70 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -37,7 +37,7 @@ namespace Microsoft.Net.Http.Server factory = new LoggerFactory(); } - return factory.Create(type.FullName); + return factory.CreateLogger(type.FullName); } internal static void LogInfo(ILogger logger, string data) @@ -48,7 +48,7 @@ namespace Microsoft.Net.Http.Server } else { - logger.WriteInformation(data); + logger.LogInformation(data); } } @@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Server } else { - logger.WriteVerbose(data); + logger.LogVerbose(data); } } @@ -72,7 +72,7 @@ namespace Microsoft.Net.Http.Server } else { - logger.WriteError(location, exception); + logger.LogError(location, exception); } } @@ -84,7 +84,7 @@ namespace Microsoft.Net.Http.Server } else { - logger.WriteError(location + "; " + message); + logger.LogError(location + "; " + message); } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index bee0c09df9..938b694355 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -149,7 +149,7 @@ namespace Microsoft.Net.Http.Server if (_requestContext.Logger.IsEnabled(LogLevel.Verbose)) { - RequestContext.Logger.WriteVerbose(new ReceiveRequestLogContext(this)); + RequestContext.Logger.LogVerbose(new ReceiveRequestLogContext(this)); } } @@ -514,14 +514,13 @@ namespace Microsoft.Net.Http.Server } } - private class ReceiveRequestLogContext : LoggerStructureBase + private class ReceiveRequestLogContext : ReflectionBasedLogValues { private readonly Request _request; internal ReceiveRequestLogContext(Request request) { _request = request; - Message = "Received Request"; } public string Method { get { return _request.Method; } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index c1a3c7b373..50be415fcc 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -366,7 +366,7 @@ namespace Microsoft.Net.Http.Server if (RequestContext.Logger.IsEnabled(LogLevel.Verbose)) { - RequestContext.Logger.WriteVerbose(new SendResponseLogContext(this)); + RequestContext.Logger.LogVerbose(new SendResponseLogContext(this)); } /* @@ -845,14 +845,13 @@ namespace Microsoft.Net.Http.Server } } - private class SendResponseLogContext : LoggerStructureBase + private class SendResponseLogContext : ReflectionBasedLogValues { private readonly Response _response; internal SendResponseLogContext(Response response) { _response = response; - Message = "Sending Response"; } public string Protocol { get { return "HTTP/1.1"; } } // HTTP.SYS only allows 1.1 responses. From 74ea7f723d6b915707ec2d56d1a36994ef095694 Mon Sep 17 00:00:00 2001 From: Praburaj Date: Thu, 5 Mar 2015 16:35:00 -0800 Subject: [PATCH 167/597] Rename Microsoft.AspNet.Http.Interfaces => Microsoft.AspNet.Http --- .../AuthenticationHandler.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 4 ++-- .../HttpsTests.cs | 2 +- .../OpaqueUpgradeTests.cs | 1 - .../RequestTests.cs | 4 ++-- .../ResponseHeaderTests.cs | 2 +- .../ResponseSendFileTests.cs | 2 +- .../ResponseTests.cs | 2 +- .../WebSocketTests.cs | 1 - 9 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index 7d2f8cd4e5..833561b30a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -26,7 +26,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Interfaces.Authentication; +using Microsoft.AspNet.Http.Authentication; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 2d1e40c6b5..48d8c23ffb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -25,8 +25,8 @@ using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http.Interfaces; -using Microsoft.AspNet.Http.Interfaces.Authentication; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Authentication; using Microsoft.Net.Http.Server; using Microsoft.Net.WebSockets; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 8b8f4e5c35..64a2b91072 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -22,8 +22,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 134ec54729..189cc35c90 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -25,7 +25,6 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.Http.Interfaces; using Microsoft.AspNet.Testing.xunit; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 47bbb4d63d..e87b8c0940 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,8 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.Http.Interfaces; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 987b767bb6..56cf7214ee 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -21,8 +21,8 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 8052698f5b..4da7f00ee9 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -25,8 +25,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index 055f3f606d..17ddeb7137 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -20,8 +20,8 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.Http.Interfaces; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index 777fe69607..c486371ea0 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -23,7 +23,6 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Core; -using Microsoft.AspNet.Http.Interfaces; using Microsoft.AspNet.Testing.xunit; using Xunit; From 099494c5d345d4af21600c6a1ba0b660817dd9e3 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Sun, 8 Mar 2015 13:00:33 -0700 Subject: [PATCH 168/597] Update aspnet50/aspnetcore50 => dnx451/dnxcore50. --- samples/HelloWorld/project.json | 6 ++--- samples/HotAddSample/project.json | 4 +-- samples/SelfHostServer/project.json | 6 ++--- .../project.json | 6 ++--- .../AuthenticationManager.cs | 4 +-- .../NativeInterop/ComNetOS.cs | 4 +-- .../NativeInterop/HttpSysSettings.cs | 8 +++--- .../NativeInterop/NclUtilities.cs | 4 +-- .../NativeInterop/UnsafeNativeMethods.cs | 26 +++++++++---------- .../RequestProcessing/OpaqueStream.cs | 6 ++--- .../RequestProcessing/RequestStream.cs | 10 +++---- .../RequestProcessing/RequestUriBuilder.cs | 4 +-- .../RequestProcessing/Response.cs | 4 +-- .../RequestProcessing/ResponseStream.cs | 8 +++--- .../ResponseStreamAsyncResult.cs | 4 +-- .../TimeoutManager.cs | 4 +-- src/Microsoft.Net.Http.Server/WebListener.cs | 10 +++---- .../WebListenerException.cs | 4 +-- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 4 +-- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 4 +-- .../fx/System/Diagnostics/TraceEventType.cs | 4 +-- .../fx/System/ExternDll.cs | 6 ++--- .../InteropServices/ExternalException.cs | 4 +-- .../fx/System/SafeNativeMethods.cs | 4 +-- src/Microsoft.Net.Http.Server/project.json | 6 ++--- .../NativeInterop/SafeNativeOverlapped.cs | 4 +-- .../NativeInterop/UnsafeNativeMethods.cs | 10 +++---- src/Microsoft.Net.WebSockets/WebSocketBase.cs | 8 +++--- .../WebSocketBuffer.cs | 4 +-- .../WebSocketException.cs | 4 +-- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 4 +-- .../fx/System/AccessViolationException.cs | 4 +-- .../System/ComponentModel/Win32Exception.cs | 4 +-- .../fx/System/ExternDll.cs | 6 ++--- .../InteropServices/ExternalException.cs | 4 +-- .../fx/System/SafeNativeMethods.cs | 4 +-- .../fx/System/SystemException.cs | 4 +-- src/Microsoft.Net.WebSockets/project.json | 4 +-- .../RequestBodyTests.cs | 4 +-- .../project.json | 4 +-- .../RequestBodyTests.cs | 4 +-- .../project.json | 4 +-- 42 files changed, 117 insertions(+), 117 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 9ef42357b6..3f7f295998 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,10 +1,10 @@ -{ +{ "dependencies": { "Microsoft.Net.Http.Server": "1.0.0-*" }, "frameworks": { - "aspnet50": { }, - "aspnetcore50": { + "dnx451": { }, + "dnxcore50": { "dependencies": { "System.Collections": "4.0.10-beta-*", "System.Console": "4.0.0-beta-*", diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index ab2ef37210..600caefcbd 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -17,7 +17,7 @@ "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:12345" }, "frameworks" : { - "aspnet50" : { }, - "aspnetcore50" : { } + "dnx451" : { }, + "dnxcore50" : { } } } diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index aded313626..bffc397397 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,4 +1,4 @@ -{ +{ "webroot": "wwwroot", "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", @@ -7,7 +7,7 @@ }, "commands": { "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:8080" }, "frameworks": { - "aspnet50": { }, - "aspnetcore50": { } + "dnx451": { }, + "dnxcore50": { } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index e1ae35960c..b0fc4b60e9 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { @@ -15,7 +15,7 @@ "allowUnsafe": true }, "frameworks": { - "aspnet50": { }, - "aspnetcore50": { } + "dnx451": { }, + "dnxcore50": { } } } diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index adb806c0af..d0a43e5dd1 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,7 +38,7 @@ namespace Microsoft.Net.Http.Server /// public sealed class AuthenticationManager { -#if ASPNETCORE50 +#if DNXCORE50 private static readonly int AuthInfoSize = Marshal.SizeOf(); #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index 030b152caa..8a6a9d3b8f 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server static ComNetOS() { -#if ASPNETCORE50 +#if DNXCORE50 // TODO: SkipIOCPCallbackOnSuccess doesn't work on Win7. Need a way to detect Win7 vs 8+. IsWin8orLater = false; #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs index 1d6daab69d..7af55371da 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Security; -#if !ASPNETCORE50 +#if !DNXCORE50 using Microsoft.Win32; #endif @@ -34,7 +34,7 @@ namespace Microsoft.Net.Http.Server { internal static class HttpSysSettings { -#if !ASPNETCORE50 +#if !DNXCORE50 private const string HttpSysParametersKey = @"System\CurrentControlSet\Services\HTTP\Parameters"; #endif private const bool EnableNonUtf8Default = true; @@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server } private static void ReadHttpSysRegistrySettings() -#if ASPNETCORE50 +#if DNXCORE50 { } #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs index 2e6d3c4b07..5514a946e6 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server get { return Environment.HasShutdownStarted -#if !ASPNETCORE50 +#if !DNXCORE50 || AppDomain.CurrentDomain.IsFinalizingForUnload() #endif ; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index 262f327bc1..054375cee9 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server { private const string HTTPAPI = "httpapi.dll"; -#if ASPNETCORE50 +#if DNXCORE50 private const string sspicli_LIB = "sspicli.dll"; private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-1.dll"; @@ -59,21 +59,21 @@ namespace Microsoft.Net.Http.Server internal const uint ERROR_CONNECTION_INVALID = 1229; } -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_processthreads_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #endif internal static extern uint GetCurrentThreadId(); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_io_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #endif internal static unsafe extern uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_kernel32_legacy_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] @@ -90,7 +90,7 @@ namespace Microsoft.Net.Http.Server internal static class SafeNetHandles { -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] @@ -98,7 +98,7 @@ namespace Microsoft.Net.Http.Server internal static extern int FreeContextBuffer( [In] IntPtr contextBuffer); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] @@ -115,21 +115,21 @@ namespace Microsoft.Net.Http.Server [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern bool CloseHandle(IntPtr handle); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_heap_obsolete_LIB, EntryPoint = "LocalAlloc", SetLastError = true)] #else [DllImport(KERNEL32, EntryPoint = "LocalAlloc", SetLastError = true)] @@ -137,21 +137,21 @@ namespace Microsoft.Net.Http.Server internal static extern SafeLocalFreeChannelBinding LocalAllocChannelBinding(int uFlags, UIntPtr sizetdwBytes); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern IntPtr LocalFree(IntPtr handle); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #endif internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs index 9d6ab5bf03..2dd9c0b4ee 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -109,7 +109,7 @@ namespace Microsoft.Net.Http.Server { return _requestStream.ReadByte(); } -#if !ASPNETCORE50 +#if !DNXCORE50 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _requestStream.BeginRead(buffer, offset, count, callback, state); @@ -143,7 +143,7 @@ namespace Microsoft.Net.Http.Server { _responseStream.WriteByte(value); } -#if !ASPNETCORE50 +#if !DNXCORE50 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _responseStream.BeginWrite(buffer, offset, count, callback, state); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index cbeaa2fb70..d32cb546be 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -198,7 +198,7 @@ namespace Microsoft.Net.Http.Server } } -#if ASPNETCORE50 +#if DNXCORE50 public unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -291,7 +291,7 @@ namespace Microsoft.Net.Http.Server return asyncResult; } -#if ASPNETCORE50 +#if DNXCORE50 public int EndRead(IAsyncResult asyncResult) #else public override int EndRead(IAsyncResult asyncResult) @@ -426,7 +426,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if ASPNETCORE50 +#if DNXCORE50 public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -435,7 +435,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if ASPNETCORE50 +#if DNXCORE50 public void EndWrite(IAsyncResult asyncResult) #else public override void EndWrite(IAsyncResult asyncResult) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index a9301ea464..2bd1cf2b6d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -70,7 +70,7 @@ namespace Microsoft.Net.Http.Server // TODO: False triggers more detailed/correct parsing, but it's rather slow. UseCookedRequestUrl = true; // SettingsSectionInternal.Section.HttpListenerUnescapeRequestUrl; Utf8Encoding = new UTF8Encoding(false, true); -#if ASPNETCORE50 +#if DNXCORE50 AnsiEncoding = Utf8Encoding; #else AnsiEncoding = Encoding.GetEncoding(0, new EncoderExceptionFallback(), new DecoderExceptionFallback()); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 50be415fcc..0ab02518a4 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -709,7 +709,7 @@ namespace Microsoft.Net.Http.Server knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = -#if ASPNETCORE50 +#if DNXCORE50 (uint)Marshal.SizeOf(); #else (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index cbe64f4330..feec8feb6f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -195,7 +195,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } -#if !ASPNETCORE50 +#if !DNXCORE50 public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); @@ -360,7 +360,7 @@ namespace Microsoft.Net.Http.Server // TODO: Verbose log data written } -#if ASPNETCORE50 +#if DNXCORE50 public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -465,7 +465,7 @@ namespace Microsoft.Net.Http.Server return asyncResult; } -#if ASPNETCORE50 +#if DNXCORE50 public void EndWrite(IAsyncResult asyncResult) #else public override void EndWrite(IAsyncResult asyncResult) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index c7b71d2aed..16c2e2128c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -140,7 +140,7 @@ namespace Microsoft.Net.Http.Server overlapped.AsyncResult = this; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. -#if ASPNETCORE50 +#if DNXCORE50 _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. #else // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index 29160fe402..6ef2ca5b7a 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,7 +35,7 @@ namespace Microsoft.Net.Http.Server /// public sealed class TimeoutManager { -#if ASPNETCORE50 +#if DNXCORE50 private static readonly int TimeoutLimitSize = Marshal.SizeOf(); #else diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 3185a414db..856a77fb69 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,7 +41,7 @@ namespace Microsoft.Net.Http.Server public sealed class WebListener : IDisposable { private const long DefaultRequestQueueLength = 1000; // Http.sys default. -#if ASPNETCORE50 +#if DNXCORE50 private static readonly int RequestChannelBindStatusSize = Marshal.SizeOf(); private static readonly int BindingInfoSize = @@ -749,7 +749,7 @@ namespace Microsoft.Net.Http.Server knownHeaderInfo[httpResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[httpResponse.ResponseInfoCount].Length = -#if ASPNETCORE50 +#if DNXCORE50 (uint)Marshal.SizeOf(); #else (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); @@ -841,7 +841,7 @@ namespace Microsoft.Net.Http.Server private static int GetTokenOffsetFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); -#if ASPNETCORE50 +#if DNXCORE50 IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); #else IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelToken")); @@ -853,7 +853,7 @@ namespace Microsoft.Net.Http.Server private static int GetTokenSizeFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); -#if ASPNETCORE50 +#if DNXCORE50 return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); #else return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelTokenSize")); diff --git a/src/Microsoft.Net.Http.Server/WebListenerException.cs b/src/Microsoft.Net.Http.Server/WebListenerException.cs index 0b31af9e66..7ad45db7eb 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerException.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,7 +45,7 @@ namespace Microsoft.Net.Http.Server : base(errorCode, message) { } -#if ASPNETCORE50 +#if DNXCORE50 public int ErrorCode #else // the base class returns the HResult with this property diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs index cdfef44a33..727e8414df 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // // ==--== -#if ASPNETCORE50 +#if DNXCORE50 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 5e1b351113..01654cbb97 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // // ==--== -#if ASPNETCORE50 +#if DNXCORE50 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs index b58cb2b3b6..b51311aeca 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if ASPNETCORE50 +#if DNXCORE50 using System; using System.ComponentModel; diff --git a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs index d0c06faf22..5604c4f1fe 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if ASPNETCORE50 +#if DNXCORE50 namespace System { @@ -30,4 +30,4 @@ namespace System public const string api_ms_win_core_localization_LIB = "api-ms-win-core-localization-l2-1-0.dll"; } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs index ff4cc36e0e..89d705b071 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if ASPNETCORE50 +#if DNXCORE50 namespace System.Runtime.InteropServices { diff --git a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs index 4fdd2d425d..265ed0113a 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if ASPNETCORE50 +#if DNXCORE50 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index d7f2167571..1d9950a28a 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { @@ -10,8 +10,8 @@ }, "frameworks": { "net45": { }, - "aspnet50": { }, - "aspnetcore50": { + "dnx451": { }, + "dnxcore50": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.0-beta-*", "System.Diagnostics.Debug": "4.0.10-beta-*", diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs index 57fa75659a..b5501b0d38 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -87,7 +87,7 @@ namespace Microsoft.Net.WebSockets get { return Environment.HasShutdownStarted -#if !ASPNETCORE50 +#if !DNXCORE50 || AppDomain.CurrentDomain.IsFinalizingForUnload() #endif ; diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs index b365a0a701..c0d176fb5e 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ namespace Microsoft.Net.WebSockets { internal static class UnsafeNativeMethods { -#if ASPNETCORE50 +#if DNXCORE50 private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll"; #else private const string KERNEL32 = "kernel32.dll"; @@ -40,14 +40,14 @@ namespace Microsoft.Net.WebSockets internal static class SafeNetHandles { -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CharSet=CharSet.Unicode, SetLastError = true)] #endif internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); -#if ASPNETCORE50 +#if DNXCORE50 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] @@ -173,7 +173,7 @@ namespace Microsoft.Net.WebSockets static WebSocketProtocolComponent() { -#if ASPNETCORE50 +#if DNXCORE50 DllFileName = Path.Combine(Environment.GetEnvironmentVariable("SYSTEMROOT"), "System32", WEBSOCKET); #else DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); diff --git a/src/Microsoft.Net.WebSockets/WebSocketBase.cs b/src/Microsoft.Net.WebSockets/WebSocketBase.cs index 4254062785..0d6fa52dba 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBase.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBase.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -1103,7 +1103,7 @@ namespace Microsoft.Net.WebSockets if (thisLockTaken || sessionHandleLockTaken) { -#if !ASPNETCORE50 +#if !DNXCORE50 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -1189,7 +1189,7 @@ namespace Microsoft.Net.WebSockets Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); if (lockTaken) { -#if !ASPNETCORE50 +#if !DNXCORE50 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -2253,7 +2253,7 @@ namespace Microsoft.Net.WebSockets "'webSocket.m_KeepAliveTracker' MUST NOT be NULL at this point."); int keepAliveIntervalMilliseconds = (int)_keepAliveInterval.TotalMilliseconds; Contract.Assert(keepAliveIntervalMilliseconds > 0, "'keepAliveIntervalMilliseconds' MUST be POSITIVE."); -#if ASPNETCORE50 +#if DNXCORE50 _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); #else if (ExecutionContext.IsFlowSuppressed()) diff --git a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs index 62323a106f..8230117bc6 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -50,7 +50,7 @@ namespace Microsoft.Net.WebSockets public const int MinSendBufferSize = 16; internal const int MinReceiveBufferSize = 256; internal const int MaxBufferSize = 64 * 1024; -#if ASPNETCORE50 +#if DNXCORE50 private static readonly int SizeOfUInt = Marshal.SizeOf(); private static readonly int SizeOfBool = Marshal.SizeOf(); #else diff --git a/src/Microsoft.Net.WebSockets/WebSocketException.cs b/src/Microsoft.Net.WebSockets/WebSocketException.cs index 6dd5d72c73..a8f0b34c45 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketException.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; namespace Microsoft.Net.WebSockets { -#if !ASPNETCORE50 +#if !DNXCORE50 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] #endif internal sealed class WebSocketException : Win32Exception diff --git a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 5e1b351113..01654cbb97 100644 --- a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // // ==--== -#if ASPNETCORE50 +#if DNXCORE50 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs index 97e4ee049a..2baee3aab3 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if ASPNETCORE50 +#if DNXCORE50 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs index 73f28a2b6e..2ff15c2f89 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if ASPNETCORE50 +#if DNXCORE50 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs index d0c06faf22..5604c4f1fe 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if ASPNETCORE50 +#if DNXCORE50 namespace System { @@ -30,4 +30,4 @@ namespace System public const string api_ms_win_core_localization_LIB = "api-ms-win-core-localization-l2-1-0.dll"; } } -#endif \ No newline at end of file +#endif diff --git a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs index ff4cc36e0e..89d705b071 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if ASPNETCORE50 +#if DNXCORE50 namespace System.Runtime.InteropServices { diff --git a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs index 4fdd2d425d..265ed0113a 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if ASPNETCORE50 +#if DNXCORE50 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs index 5bcc7aeaa0..4f74937813 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if ASPNETCORE50 +#if DNXCORE50 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index b36dc2a234..87fba4fa14 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "Implementation of WebSocket abstract base class. Used by WebListener.", "dependencies": { @@ -7,7 +7,7 @@ "compilationOptions": { "allowUnsafe": true }, "frameworks": { "net45": { }, - "aspnetcore50": { + "dnxcore50": { "dependencies": { "System.Collections": "4.0.10-beta-*", "System.Diagnostics.Contracts": "4.0.0-beta-*", diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index fefa2e0a0b..9763e76d33 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal("Hello World", response); } } -#if !ASPNETCORE50 +#if !DNXCORE50 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 76420d3c8e..b41a6fa302 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,4 +1,4 @@ -{ +{ "commands": { "test": "xunit.runner.kre" }, @@ -9,7 +9,7 @@ "xunit.runner.kre": "1.0.0-*" }, "frameworks": { - "aspnet50": { + "dnx451": { "frameworkAssemblies": { "System.Net.Http": "", "System.Net.Http.WebRequest": "" diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index 606aa6c169..98f1b28e04 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.IO; @@ -51,7 +51,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal("Hello World", response); } } -#if ASPNET50 +#if DNX451 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index f0db29a06c..9b537c0a3e 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,4 +1,4 @@ -{ +{ "commands": { "test": "xunit.runner.kre" }, @@ -8,7 +8,7 @@ "xunit.runner.kre": "1.0.0-*" }, "frameworks": { - "aspnet50": { + "dnx451": { frameworkAssemblies: { "System.Net.Http": "", "System.Net.Http.WebRequest": "" From 7649fcc769bc8a365634ac513bc77e00ec216fe5 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Sun, 8 Mar 2015 13:00:35 -0700 Subject: [PATCH 169/597] Update K_BUILD_VERSION/kre/KRE/.k => DNX_BUILD_VERSION/dnx/DNX/.dnx. --- build.cmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cmd b/build.cmd index 86ca5bbbf1..49ba0692de 100644 --- a/build.cmd +++ b/build.cmd @@ -1,4 +1,4 @@ -@echo off +@echo off cd %~dp0 SETLOCAL @@ -19,7 +19,7 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion -IF "%SKIP_KRE_INSTALL%"=="1" goto run +IF "%SKIP_DNX_INSTALL%"=="1" goto run CALL packages\KoreBuild\build\kvm upgrade -runtime CLR -x86 CALL packages\KoreBuild\build\kvm install default -runtime CoreCLR -x86 From 760744cdcd5f3f079752c8046d7868655c384b31 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Sun, 8 Mar 2015 13:00:36 -0700 Subject: [PATCH 170/597] Update kvm/KVM/Kvm => dnvm/DNVM/Dnvm. --- build.cmd | 6 +++--- build.sh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.cmd b/build.cmd index 49ba0692de..77be0a6627 100644 --- a/build.cmd +++ b/build.cmd @@ -20,9 +20,9 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion IF "%SKIP_DNX_INSTALL%"=="1" goto run -CALL packages\KoreBuild\build\kvm upgrade -runtime CLR -x86 -CALL packages\KoreBuild\build\kvm install default -runtime CoreCLR -x86 +CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -x86 +CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -x86 :run -CALL packages\KoreBuild\build\kvm use default -runtime CLR -x86 +CALL packages\KoreBuild\build\dnvm use default -runtime CLR -x86 packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh index c7873ef58e..74cb3421e6 100644 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild @@ -28,11 +28,11 @@ if test ! -d packages/KoreBuild; then fi if ! type k > /dev/null 2>&1; then - source packages/KoreBuild/build/kvm.sh + source packages/KoreBuild/build/dnvm.sh fi if ! type k > /dev/null 2>&1; then - kvm upgrade + dnvm upgrade fi mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" From cf1ad5f260029842905645d7ce99708a6d01fdf7 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Sun, 8 Mar 2015 13:00:36 -0700 Subject: [PATCH 171/597] Update build.sh to use dnvm correctly. --- build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 74cb3421e6..a9ce06d087 100644 --- a/build.sh +++ b/build.sh @@ -27,7 +27,7 @@ if test ! -d packages/KoreBuild; then mono .nuget/nuget.exe install Sake -version 0.2 -o packages -ExcludeVersion fi -if ! type k > /dev/null 2>&1; then +if ! type dnvm > /dev/null 2>&1; then source packages/KoreBuild/build/dnvm.sh fi @@ -36,3 +36,4 @@ if ! type k > /dev/null 2>&1; then fi mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" + From ad192f58835b182ea0a511f38a7781877f6a5fdc Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 9 Mar 2015 13:01:52 -0700 Subject: [PATCH 172/597] Remove BOM from project.json, *.cmd, *.sh and *.shade files. --- build.cmd | 2 +- build.sh | 2 +- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- src/Microsoft.Net.WebSockets/project.json | 2 +- .../project.json | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.cmd b/build.cmd index 77be0a6627..68a732c182 100644 --- a/build.cmd +++ b/build.cmd @@ -1,4 +1,4 @@ -@echo off +@echo off cd %~dp0 SETLOCAL diff --git a/build.sh b/build.sh index a9ce06d087..ec3263114a 100644 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 3f7f295998..a6fcd0a9bd 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,4 +1,4 @@ -{ +{ "dependencies": { "Microsoft.Net.Http.Server": "1.0.0-*" }, diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 600caefcbd..629c23df62 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,4 +1,4 @@ -{ +{ "webroot": "wwwroot", "version": "1.0.0-*", "exclude": [ diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index bffc397397..e393059098 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,4 +1,4 @@ -{ +{ "webroot": "wwwroot", "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index b0fc4b60e9..a2c09b7d69 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 1d9950a28a..ec9f673152 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 87fba4fa14..d96b50018a 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "Implementation of WebSocket abstract base class. Used by WebListener.", "dependencies": { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index b41a6fa302..db56b75e7d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,4 +1,4 @@ -{ +{ "commands": { "test": "xunit.runner.kre" }, diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 9b537c0a3e..0b4adb225e 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,4 +1,4 @@ -{ +{ "commands": { "test": "xunit.runner.kre" }, From 755ad7bd2b6556c99169ec95304c0efe8a889bb6 Mon Sep 17 00:00:00 2001 From: Praburaj Date: Tue, 10 Mar 2015 11:47:35 -0700 Subject: [PATCH 173/597] Renaming Nuget.org feed key name to Nuget. fixes https://github.com/aspnet/Universe/issues/174 --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index f41e9c631d..da57d47267 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -2,6 +2,6 @@ - + - + \ No newline at end of file From b84b0dbfac40093aea64a71dd55d0787fa62b73a Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 11 Mar 2015 14:08:56 -0700 Subject: [PATCH 174/597] Update .kproj => .xproj. --- WebListener.sln | 16 ++++++++-------- .../{HelloWorld.kproj => HelloWorld.xproj} | 0 .../{HotAddSample.kproj => HotAddSample.xproj} | 0 ...SelfHostServer.kproj => SelfHostServer.xproj} | 0 ...=> Microsoft.AspNet.Server.WebListener.xproj} | 0 ...ver.kproj => Microsoft.Net.Http.Server.xproj} | 0 ...kets.kproj => Microsoft.Net.WebSockets.xproj} | 0 ...Net.Server.WebListener.FunctionalTests.xproj} | 0 ...rosoft.Net.Http.Server.FunctionalTests.xproj} | 0 9 files changed, 8 insertions(+), 8 deletions(-) rename samples/HelloWorld/{HelloWorld.kproj => HelloWorld.xproj} (100%) rename samples/HotAddSample/{HotAddSample.kproj => HotAddSample.xproj} (100%) rename samples/SelfHostServer/{SelfHostServer.kproj => SelfHostServer.xproj} (100%) rename src/Microsoft.AspNet.Server.WebListener/{Microsoft.AspNet.Server.WebListener.kproj => Microsoft.AspNet.Server.WebListener.xproj} (100%) rename src/Microsoft.Net.Http.Server/{Microsoft.Net.Http.Server.kproj => Microsoft.Net.Http.Server.xproj} (100%) rename src/Microsoft.Net.WebSockets/{Microsoft.Net.WebSockets.kproj => Microsoft.Net.WebSockets.xproj} (100%) rename test/Microsoft.AspNet.Server.WebListener.FunctionalTests/{Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj => Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj} (100%) rename test/Microsoft.Net.Http.Server.FunctionalTests/{Microsoft.Net.Http.Server.FunctionalTests.kproj => Microsoft.Net.Http.Server.FunctionalTests.xproj} (100%) diff --git a/WebListener.sln b/WebListener.sln index ddac12e798..33443010fa 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -11,26 +11,26 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E183C826-1 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A1E31E3-2794-4CA3-B8E2-253E96BDE514}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server", "src\Microsoft.Net.Http.Server\Microsoft.Net.Http.Server.kproj", "{3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server", "src\Microsoft.Net.Http.Server\Microsoft.Net.Http.Server.xproj", "{3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\HelloWorld\HelloWorld.kproj", "{6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\HelloWorld\HelloWorld.xproj", "{6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.kproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.xproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.WebSockets", "src\Microsoft.Net.WebSockets\Microsoft.Net.WebSockets.kproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.WebSockets", "src\Microsoft.Net.WebSockets\Microsoft.Net.WebSockets.xproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj", "{4492FF4C-9032-411D-853F-46B01755E504}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj", "{4492FF4C-9032-411D-853F-46B01755E504}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.kproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.xproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server.FunctionalTests", "test\Microsoft.Net.Http.Server.FunctionalTests\Microsoft.Net.Http.Server.FunctionalTests.kproj", "{DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server.FunctionalTests", "test\Microsoft.Net.Http.Server.FunctionalTests\Microsoft.Net.Http.Server.FunctionalTests.xproj", "{DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5E9B546C-17AC-4BDF-BCB3-5955D4755ED8}" ProjectSection(SolutionItems) = preProject global.json = global.json EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HotAddSample", "samples\HotAddSample\HotAddSample.kproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HotAddSample", "samples\HotAddSample\HotAddSample.xproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/samples/HelloWorld/HelloWorld.kproj b/samples/HelloWorld/HelloWorld.xproj similarity index 100% rename from samples/HelloWorld/HelloWorld.kproj rename to samples/HelloWorld/HelloWorld.xproj diff --git a/samples/HotAddSample/HotAddSample.kproj b/samples/HotAddSample/HotAddSample.xproj similarity index 100% rename from samples/HotAddSample/HotAddSample.kproj rename to samples/HotAddSample/HotAddSample.xproj diff --git a/samples/SelfHostServer/SelfHostServer.kproj b/samples/SelfHostServer/SelfHostServer.xproj similarity index 100% rename from samples/SelfHostServer/SelfHostServer.kproj rename to samples/SelfHostServer/SelfHostServer.xproj diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.kproj rename to src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj diff --git a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj similarity index 100% rename from src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.kproj rename to src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj diff --git a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj similarity index 100% rename from src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.kproj rename to src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.kproj rename to test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj similarity index 100% rename from test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.kproj rename to test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj From b8286ec272d3f601d3ab151e31b4782003c6461b Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 11 Mar 2015 16:58:36 -0700 Subject: [PATCH 175/597] Do not use deprecated `dnvm -x86` switch --- build.cmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.cmd b/build.cmd index 68a732c182..41025afb26 100644 --- a/build.cmd +++ b/build.cmd @@ -20,9 +20,9 @@ IF EXIST packages\KoreBuild goto run .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion IF "%SKIP_DNX_INSTALL%"=="1" goto run -CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -x86 -CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -x86 +CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 :run -CALL packages\KoreBuild\build\dnvm use default -runtime CLR -x86 +CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* From 4883cfe40d9b88199c3a054adadc20b73812e518 Mon Sep 17 00:00:00 2001 From: Brennan Date: Thu, 12 Mar 2015 16:06:36 -0700 Subject: [PATCH 176/597] XRE name changes --- .../project.json | 4 ++-- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index db56b75e7d..71d430dee6 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,12 +1,12 @@ { "commands": { - "test": "xunit.runner.kre" + "test": "xunit.runner.aspnet" }, "dependencies": { "Microsoft.AspNet.Http.Core": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", - "xunit.runner.kre": "1.0.0-*" + "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "frameworks": { "dnx451": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 0b4adb225e..f2f6f8caee 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,11 +1,11 @@ { "commands": { - "test": "xunit.runner.kre" + "test": "xunit.runner.aspnet" }, "dependencies": { "Microsoft.Net.Http.Server": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", - "xunit.runner.kre": "1.0.0-*" + "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "frameworks": { "dnx451": { From efc5ea9b5de3a50734c0e789e7893fa26aa5edcb Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 16 Mar 2015 16:46:56 -0700 Subject: [PATCH 177/597] React to auth changes --- .../AuthenticationHandler.cs | 4 ++-- .../AuthenticationTests.cs | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index 833561b30a..bbaa799bca 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -52,7 +52,7 @@ namespace Microsoft.AspNet.Server.WebListener foreach (var authType in ListEnabledAuthSchemes()) { string authScheme = authType.ToString(); - if (context.AuthenticationSchemes.Contains(authScheme, StringComparer.Ordinal)) + if (string.Equals(authScheme, context.AuthenticationScheme, StringComparison.Ordinal)) { if (identity != null && identity.IsAuthenticated && string.Equals(authScheme, identity.AuthenticationType, StringComparison.Ordinal)) @@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Server.WebListener } else { - context.NotAuthenticated(authScheme, properties: null, description: GetDescription(authScheme)); + context.NotAuthenticated(); } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index e96b810101..e78cb247be 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -262,8 +262,11 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - var authResults = context.Authenticate(authTypeList); - Assert.False(authResults.Any()); + foreach (var scheme in authTypeList) + { + var authResults = context.Authenticate(scheme); + Assert.Null(authResults.Principal); + } return Task.FromResult(0); })) { @@ -289,8 +292,16 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); - var authResults = context.Authenticate(authTypeList); - Assert.Equal(1, authResults.Count()); + var count = 0; + foreach (var scheme in authTypeList) + { + var authResults = context.Authenticate(scheme); + if (authResults.Principal != null) + { + count++; + } + } + Assert.Equal(1, count); return Task.FromResult(0); })) { From b761e7d8c214e8d8689477eae8db6b3ea554ad92 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 16 Mar 2015 17:47:29 -0700 Subject: [PATCH 178/597] Fix tests to check results for null --- .../AuthenticationTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index e78cb247be..451e9387af 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -16,6 +16,7 @@ // permissions and limitations under the License. using System; +using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; @@ -265,7 +266,7 @@ namespace Microsoft.AspNet.Server.WebListener foreach (var scheme in authTypeList) { var authResults = context.Authenticate(scheme); - Assert.Null(authResults.Principal); + Assert.Null(authResults); } return Task.FromResult(0); })) @@ -296,7 +297,7 @@ namespace Microsoft.AspNet.Server.WebListener foreach (var scheme in authTypeList) { var authResults = context.Authenticate(scheme); - if (authResults.Principal != null) + if (authResults != null) { count++; } From 39b8d204fd0fac894fdfc883a84a5010c37c6371 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Mon, 23 Feb 2015 11:10:03 -0800 Subject: [PATCH 179/597] React to aspnet/HttpAbstractions#160 - Implemented OnResponseCompleted --- .../FeatureContext.cs | 5 +++ .../RequestProcessing/Response.cs | 38 +++++++++++++++++++ .../Resources.Designer.cs | 8 ++++ src/Microsoft.Net.Http.Server/Resources.resx | 3 ++ 4 files changed, 54 insertions(+) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 48d8c23ffb..b2b0906caa 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -360,6 +360,11 @@ namespace Microsoft.AspNet.Server.WebListener Response.OnSendingHeaders(callback, state); } + void IHttpResponseFeature.OnResponseCompleted(Action callback, object state) + { + Response.OnResponseCompleted(callback, state); + } + string IHttpResponseFeature.ReasonPhrase { get { return Response.ReasonPhrase; } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 0ab02518a4..be5bf38abd 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -48,6 +48,7 @@ namespace Microsoft.Net.Http.Server private BoundaryType _boundaryType; private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 _nativeResponse; private IList, object>> _onSendingHeadersActions; + private IList, object>> _onResponseCompletedActions; private RequestContext _requestContext; @@ -63,6 +64,7 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.Version.MinorVersion = 1; _responseState = ResponseState.Created; _onSendingHeadersActions = new List, object>>(); + _onResponseCompletedActions = new List, object>>(); } private enum ResponseState @@ -284,6 +286,7 @@ namespace Microsoft.Net.Http.Server { return; } + NotifyOnResponseCompleted(); // TODO: Verbose log EnsureResponseStream(); _nativeStream.Dispose(); @@ -829,6 +832,17 @@ namespace Microsoft.Net.Http.Server actions.Add(new Tuple, object>(callback, state)); } + public void OnResponseCompleted(Action callback, object state) + { + var actions = _onResponseCompletedActions; + if (actions == null) + { + throw new InvalidOperationException("Response already completed"); + } + + actions.Add(new Tuple, object>(callback, state)); + } + private void NotifyOnSendingHeaders() { var actions = Interlocked.Exchange(ref _onSendingHeadersActions, null); @@ -845,6 +859,30 @@ namespace Microsoft.Net.Http.Server } } + private void NotifyOnResponseCompleted() + { + var actions = Interlocked.Exchange(ref _onResponseCompletedActions, null); + if (actions == null) + { + // Something threw the first time, do not try again. + return; + } + + foreach (var actionPair in actions) + { + try + { + actionPair.Item1(actionPair.Item2); + } + catch (Exception ex) + { + RequestContext.Logger.LogWarning( + String.Format(Resources.Warning_ExceptionInOnResponseCompletedAction, nameof(OnResponseCompleted)), + ex); + } + } + } + private class SendResponseLogContext : ReflectionBasedLogValues { private readonly Response _response; diff --git a/src/Microsoft.Net.Http.Server/Resources.Designer.cs b/src/Microsoft.Net.Http.Server/Resources.Designer.cs index 0d5dffd0c3..cee3ec2600 100644 --- a/src/Microsoft.Net.Http.Server/Resources.Designer.cs +++ b/src/Microsoft.Net.Http.Server/Resources.Designer.cs @@ -166,5 +166,13 @@ namespace Microsoft.Net.Http.Server { return ResourceManager.GetString("Exception_WrongIAsyncResult", resourceCulture); } } + + /// + /// An exception occured while running an action registered with {0}. + /// + internal static string Warning_ExceptionInOnResponseCompletedAction + { + get { return ResourceManager.GetString("Warning_ExceptionInOnResponseCompletedAction"); } + } } } diff --git a/src/Microsoft.Net.Http.Server/Resources.resx b/src/Microsoft.Net.Http.Server/Resources.resx index 005bafca2f..67b954a934 100644 --- a/src/Microsoft.Net.Http.Server/Resources.resx +++ b/src/Microsoft.Net.Http.Server/Resources.resx @@ -147,4 +147,7 @@ The given IAsyncResult does not match this opperation. + + An exception occured while running an action registered with {0}. + \ No newline at end of file From 30232279fdfd44bb688fc0614f33b5be3b9f42bc Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 24 Mar 2015 21:46:51 -0700 Subject: [PATCH 180/597] Remove k command and use dnx instead --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index ec3263114a..d81164353c 100644 --- a/build.sh +++ b/build.sh @@ -31,7 +31,7 @@ if ! type dnvm > /dev/null 2>&1; then source packages/KoreBuild/build/dnvm.sh fi -if ! type k > /dev/null 2>&1; then +if ! type dnx > /dev/null 2>&1; then dnvm upgrade fi From 0c1e23430549863d70a83fa3e265017dc7f6f689 Mon Sep 17 00:00:00 2001 From: suhasj Date: Wed, 25 Mar 2015 11:47:54 -0700 Subject: [PATCH 181/597] Updating to release NuGet.config --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index da57d47267..1978dc065a 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@  - + - \ No newline at end of file + From fe165bbafcd222beda687181b34c41e03c75326e Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Sun, 29 Mar 2015 10:38:39 -0700 Subject: [PATCH 182/597] Rename "dnu bundle" to "dnu publish" --- samples/HotAddSample/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 629c23df62..9958bf45fb 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -4,7 +4,7 @@ "exclude": [ "wwwroot" ], - "bundleExclude": [ + "publishExclude": [ "**.kproj", "**.user", "**.vspscc" From 1c40229e8caa972bf987fcd1dea4b5d306d30187 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Wed, 1 Apr 2015 03:18:58 -0700 Subject: [PATCH 183/597] React to hosting changes --- .gitignore | 1 + WebListener.sln | 2 +- .../AssemblyNeutralAttribute.cs | 27 ------------------- .../project.json | 4 +-- 4 files changed, 4 insertions(+), 30 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs diff --git a/.gitignore b/.gitignore index ac82da7568..2f2c21bf2e 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ nuget.exe *.ipch *.sln.ide project.lock.json +/.vs \ No newline at end of file diff --git a/WebListener.sln b/WebListener.sln index 33443010fa..9f9ffbfbf5 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22310.1 +VisualStudioVersion = 14.0.22710.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject diff --git a/src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs b/src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs deleted file mode 100644 index cb5384455b..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/AssemblyNeutralAttribute.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -using System; - -namespace Microsoft.Net.Runtime -{ - [AssemblyNeutralAttribute] - [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] - public sealed class AssemblyNeutralAttribute : Attribute - { - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index a2c09b7d69..84662df4bc 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -5,8 +5,8 @@ "Microsoft.AspNet.FeatureModel": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Http.Interfaces": "1.0.0-*", - "Microsoft.AspNet.Hosting.Interfaces": "1.0.0-*", - "Microsoft.Framework.ConfigurationModel": "1.0.0-*", + "Microsoft.AspNet.Server.Interfaces": "1.0.0-*", + "Microsoft.Framework.ConfigurationModel.Interfaces": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*", "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" From 3ebff3a957ed58b6e1684f834b1c79ea9665182f Mon Sep 17 00:00:00 2001 From: David Fowler Date: Wed, 1 Apr 2015 03:46:10 -0700 Subject: [PATCH 184/597] React to hosting changes again --- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 84662df4bc..8946c59288 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -5,7 +5,7 @@ "Microsoft.AspNet.FeatureModel": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Http.Interfaces": "1.0.0-*", - "Microsoft.AspNet.Server.Interfaces": "1.0.0-*", + "Microsoft.AspNet.Hosting.Server.Interfaces": "1.0.0-*", "Microsoft.Framework.ConfigurationModel.Interfaces": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*", From d70636b5116d04ddd912e4d79db87a30f295281e Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 1 Apr 2015 15:58:45 -0700 Subject: [PATCH 185/597] Add travis and appveyor CI support. --- .travis.yml | 3 +++ appveyor.yml | 5 +++++ build.sh | 0 3 files changed, 8 insertions(+) create mode 100644 .travis.yml create mode 100644 appveyor.yml mode change 100644 => 100755 build.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..0f4cb93e59 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: csharp +script: + - ./build.sh verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..88cb9ef145 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,5 @@ +build_script: + - build.cmd verify +clone_depth: 1 +test: off +deploy: off \ No newline at end of file diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 From 706fc8ddbdb8fadbd07a54d849292cab5ffd276a Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 1 Apr 2015 17:09:42 -0700 Subject: [PATCH 186/597] Turn off sudo for .travis.yml. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0f4cb93e59..5939a529e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ language: csharp +sudo: false script: - ./build.sh verify \ No newline at end of file From 8e79c11c96cc11b997bf2ca6ba760438dbc99f92 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 2 Apr 2015 09:20:46 -0700 Subject: [PATCH 187/597] Update global.json, sources=>projects --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 840c36f6ad..983ba0401e 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,3 @@ { - "sources": ["src"] -} \ No newline at end of file + "projects": ["src"] +} From a2014e32c042fcadbb57a68868c9b2e6d570bd15 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 2 Apr 2015 12:10:01 -0700 Subject: [PATCH 188/597] Clean up samples so they work with current tooling. --- samples/HelloWorld/Program.cs | 17 ----------------- .../HelloWorld/Properties/launchSettings.json | 9 +++++++++ samples/HelloWorld/project.json | 3 +++ .../Properties/launchSettings.json | 9 +++++++++ samples/HotAddSample/Startup.cs | 11 +++++++---- samples/HotAddSample/project.json | 12 ++---------- .../Properties/launchSettings.json | 9 +++++++++ samples/SelfHostServer/SelfHostServer.xproj | 3 +-- samples/SelfHostServer/Startup.cs | 18 ------------------ samples/SelfHostServer/project.json | 1 - samples/TestClient/Program.cs | 17 ----------------- 11 files changed, 40 insertions(+), 69 deletions(-) create mode 100644 samples/HelloWorld/Properties/launchSettings.json create mode 100644 samples/HotAddSample/Properties/launchSettings.json create mode 100644 samples/SelfHostServer/Properties/launchSettings.json diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index e693458753..eb57deedfc 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -1,20 +1,3 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - using System; using System.Net.WebSockets; using System.Text; diff --git a/samples/HelloWorld/Properties/launchSettings.json b/samples/HelloWorld/Properties/launchSettings.json new file mode 100644 index 0000000000..6161971048 --- /dev/null +++ b/samples/HelloWorld/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "sample": { + "commandName": "sample", + "launchBrowser": true, + "launchUrl": "http://localhost:8080" + } + } +} \ No newline at end of file diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index a6fcd0a9bd..940c50ed47 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -2,6 +2,9 @@ "dependencies": { "Microsoft.Net.Http.Server": "1.0.0-*" }, + "commands": { + "sample": "HelloWorld" + }, "frameworks": { "dnx451": { }, "dnxcore50": { diff --git a/samples/HotAddSample/Properties/launchSettings.json b/samples/HotAddSample/Properties/launchSettings.json new file mode 100644 index 0000000000..62f539fadd --- /dev/null +++ b/samples/HotAddSample/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "web": { + "commandName": "web", + "launchBrowser": true, + "launchUrl": "http://localhost:12345" + } + } +} \ No newline at end of file diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index 2092308438..e1424665a4 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Server.WebListener; +using Microsoft.Framework.Logging; namespace HotAddSample { @@ -10,8 +11,10 @@ namespace HotAddSample // will be reset before the end of the request. public class Startup { - public void Configure(IApplicationBuilder app) + public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { + loggerfactory.AddConsole(LogLevel.Information); + var server = (ServerInformation)app.Server; var listener = server.Listener; listener.UrlPrefixes.Add("http://localhost:12346/pathBase/"); @@ -34,7 +37,7 @@ namespace HotAddSample await context.Response.WriteAsync("Error adding: " + toAdd + "
"); await context.Response.WriteAsync(ex.ToString().Replace(Environment.NewLine, "
")); } - await context.Response.WriteAsync("
back"); + await context.Response.WriteAsync("
back"); await context.Response.WriteAsync(""); return; } @@ -58,7 +61,7 @@ namespace HotAddSample { await context.Response.WriteAsync("Not found: " + toRemove); } - await context.Response.WriteAsync("
back"); + await context.Response.WriteAsync("
back"); await context.Response.WriteAsync(""); return; } @@ -75,7 +78,7 @@ namespace HotAddSample await context.Response.WriteAsync("" + prefix + " (remove)
"); } - await context.Response.WriteAsync("
"); + await context.Response.WriteAsync(""); await context.Response.WriteAsync(""); await context.Response.WriteAsync(""); await context.Response.WriteAsync("
"); diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 9958bf45fb..cfc1678585 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,17 +1,9 @@ { - "webroot": "wwwroot", "version": "1.0.0-*", - "exclude": [ - "wwwroot" - ], - "publishExclude": [ - "**.kproj", - "**.user", - "**.vspscc" - ], "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", - "Microsoft.AspNet.Server.WebListener": "1.0.0-*" + "Microsoft.AspNet.Server.WebListener": "1.0.0-*", + "Microsoft.Framework.Logging.Console": "1.0.0-*" }, "commands": { "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:12345" diff --git a/samples/SelfHostServer/Properties/launchSettings.json b/samples/SelfHostServer/Properties/launchSettings.json new file mode 100644 index 0000000000..bca9b1f442 --- /dev/null +++ b/samples/SelfHostServer/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "web": { + "commandName": "web", + "launchBrowser": true, + "launchUrl": "http://localhost:8080" + } + } +} \ No newline at end of file diff --git a/samples/SelfHostServer/SelfHostServer.xproj b/samples/SelfHostServer/SelfHostServer.xproj index e67781baec..a744f48383 100644 --- a/samples/SelfHostServer/SelfHostServer.xproj +++ b/samples/SelfHostServer/SelfHostServer.xproj @@ -12,7 +12,6 @@ 2.0 - 59517 - + \ No newline at end of file diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 1597e5628b..ce7464d85f 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -1,20 +1,3 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - using System; using System.Net.WebSockets; using System.Text; @@ -23,7 +6,6 @@ using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Server.WebListener; using Microsoft.Framework.Logging; -using Microsoft.Framework.Logging.Console; using Microsoft.Net.Http.Server; namespace SelfHostServer diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index e393059098..d8a3b0a190 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,5 +1,4 @@ { - "webroot": "wwwroot", "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", diff --git a/samples/TestClient/Program.cs b/samples/TestClient/Program.cs index 166bb64767..a85e2fc5c4 100644 --- a/samples/TestClient/Program.cs +++ b/samples/TestClient/Program.cs @@ -1,20 +1,3 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - using System; using System.Net; using System.Net.Http; From 626ed7398792750585438d972b5d37e157aba016 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 2 Apr 2015 13:49:31 -0700 Subject: [PATCH 189/597] Update .xproj files for Microsoft.Web.AspNet.* -> Microsoft.DNX.* rename --- samples/HelloWorld/HelloWorld.xproj | 8 ++++---- samples/HotAddSample/HotAddSample.xproj | 8 ++++---- samples/SelfHostServer/SelfHostServer.xproj | 6 +++--- .../Microsoft.AspNet.Server.WebListener.xproj | 8 ++++---- .../Microsoft.Net.Http.Server.xproj | 8 ++++---- .../Microsoft.Net.WebSockets.xproj | 8 ++++---- ...rosoft.AspNet.Server.WebListener.FunctionalTests.xproj | 8 ++++---- .../Microsoft.Net.Http.Server.FunctionalTests.xproj | 8 ++++---- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/samples/HelloWorld/HelloWorld.xproj b/samples/HelloWorld/HelloWorld.xproj index b617afbdb3..839db9da9c 100644 --- a/samples/HelloWorld/HelloWorld.xproj +++ b/samples/HelloWorld/HelloWorld.xproj @@ -1,10 +1,10 @@ - + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 6daf3e6b-8e1b-4e6e-b9fe-7b1e5fdb7db4 ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - - + + \ No newline at end of file diff --git a/samples/HotAddSample/HotAddSample.xproj b/samples/HotAddSample/HotAddSample.xproj index 04ffc32bb5..efa6f91d2b 100644 --- a/samples/HotAddSample/HotAddSample.xproj +++ b/samples/HotAddSample/HotAddSample.xproj @@ -1,10 +1,10 @@ - + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 8bfa392a-8b67-4454-916b-67c545edfaef ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - - + + \ No newline at end of file diff --git a/samples/SelfHostServer/SelfHostServer.xproj b/samples/SelfHostServer/SelfHostServer.xproj index e67781baec..6c6aedde22 100644 --- a/samples/SelfHostServer/SelfHostServer.xproj +++ b/samples/SelfHostServer/SelfHostServer.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 1236f93a-ac5c-4a77-9477-c88f040151ca ..\..\artifacts\obj\$(MSBuildProjectName) @@ -14,5 +14,5 @@ 2.0 59517 - - + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj index 4292c1d7dc..cba373f53a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj +++ b/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj @@ -1,10 +1,10 @@ - + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + b9f45f9d-d206-47f0-8e5f-54ce2f0bdf92 ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - - + + \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj index 99200daf9a..9966c5c657 100644 --- a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj +++ b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj @@ -1,10 +1,10 @@ - + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - - + + \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj index 1f1ed03bcf..bfc3ead68e 100644 --- a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj +++ b/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj @@ -1,10 +1,10 @@ - + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + e788aeae-2cb4-4bfa-8746-d0bb7e93a1bb ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - - + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj index 4d35f3ef98..80131fc053 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj @@ -1,10 +1,10 @@ - + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 4492ff4c-9032-411d-853f-46b01755e504 ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - - + + \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj index 3d2f7da25f..010e267757 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj @@ -1,10 +1,10 @@ - + 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + dcb6e0b1-223d-44e6-8696-4767e5b6e6a1 ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - - + + \ No newline at end of file From 82f69344d8a072f6620c268da893fa455a91b4fc Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Fri, 3 Apr 2015 17:35:48 -0700 Subject: [PATCH 190/597] Fix AppVeyor git line ending config --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 88cb9ef145..3fab83e134 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,5 @@ +init: + - git config --global core.autocrlf true build_script: - build.cmd verify clone_depth: 1 From e6ddbb929c06babca20d6dc9cddc5f192cfce346 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Sat, 4 Apr 2015 04:08:41 -0700 Subject: [PATCH 191/597] Reacting to ILogger api changes --- src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs | 2 +- src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 938b694355..37f604079d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -530,7 +530,7 @@ namespace Microsoft.Net.Http.Server public string Protocol { get { return "HTTP/" + _request.ProtocolVersion.ToString(2); } } public IEnumerable Headers { get { return new HeadersLogStructure(_request.Headers); } } - public override string Format() + public override string ToString() { var requestBuilder = new StringBuilder("Received request: "); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index be5bf38abd..f4793e9e01 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -897,7 +897,7 @@ namespace Microsoft.Net.Http.Server public string ReasonPhrase { get { return _response.ReasonPhrase ?? _response.GetReasonPhrase(_response.StatusCode); } } public IEnumerable Headers { get { return new HeadersLogStructure(_response.Headers); } } - public override string Format() + public override string ToString() { // HTTP/1.1 200 OK var responseBuilder = new StringBuilder("Sending Response: "); From 4cc499540a1aa3b70f3bdf7cf0fdaf2e5c061dd4 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 7 Apr 2015 14:54:01 -0700 Subject: [PATCH 192/597] Add serviceable attribute to projects. aspnet/DNX#1600 --- .../Properties/AssemblyInfo.cs | 6 ++++++ src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs | 6 ++++++ src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs | 6 ++++++ 3 files changed, 18 insertions(+) create mode 100644 src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..f5c6f4a83a --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection; + +[assembly: AssemblyMetadata("Serviceable", "True")] \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..f5c6f4a83a --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection; + +[assembly: AssemblyMetadata("Serviceable", "True")] \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs b/src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..f5c6f4a83a --- /dev/null +++ b/src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection; + +[assembly: AssemblyMetadata("Serviceable", "True")] \ No newline at end of file From 2ead53e8eb5fcd50896e8fab5fceddf5a575fd2c Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 7 Apr 2015 16:17:54 -0700 Subject: [PATCH 193/597] Update .travis.yml and appveyor.yml to build quietly. --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5939a529e5..947bf868ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: csharp sudo: false script: - - ./build.sh verify \ No newline at end of file + - ./build.sh --quiet verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 3fab83e134..636a7618d3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ init: - git config --global core.autocrlf true build_script: - - build.cmd verify + - build.cmd --quiet verify clone_depth: 1 test: off deploy: off \ No newline at end of file From 0e5c83c4023bf911fd9ed30af579cd68a7b54565 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 8 Apr 2015 14:41:58 -0700 Subject: [PATCH 194/597] Replace WebSocket dependency. --- src/Microsoft.AspNet.Server.WebListener/project.json | 3 +-- src/Microsoft.Net.WebSockets/project.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 8946c59288..3d37438cbb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -8,8 +8,7 @@ "Microsoft.AspNet.Hosting.Server.Interfaces": "1.0.0-*", "Microsoft.Framework.ConfigurationModel.Interfaces": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", - "Microsoft.Net.Http.Server": "1.0.0-*", - "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" + "Microsoft.Net.Http.Server": "1.0.0-*" }, "compilationOptions": { "allowUnsafe": true diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index d96b50018a..d78a9994f2 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "description": "Implementation of WebSocket abstract base class. Used by WebListener.", "dependencies": { - "Microsoft.Net.WebSocketAbstractions": "1.0.0-*" }, "compilationOptions": { "allowUnsafe": true }, "frameworks": { @@ -15,6 +14,7 @@ "System.IO": "4.0.10-beta-*", "System.Linq": "4.0.0-beta-*", "System.Net.Primitives": "4.0.10-beta-*", + "System.Net.WebSockets": "4.0.0-beta-*", "System.Resources.ResourceManager": "4.0.0-beta-*", "System.Runtime.Extensions": "4.0.10-beta-*", "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", From 9de989fd54e2662745a0603ad1b193167b14f940 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 9 Apr 2015 04:27:42 -0700 Subject: [PATCH 195/597] Removed unnecessary dependencies --- src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs | 1 - src/Microsoft.AspNet.Server.WebListener/project.json | 5 +---- src/Microsoft.Net.Http.Server/project.json | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs index 314b60e336..a6414b115a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -17,7 +17,6 @@ using System.Reflection; using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Http; namespace Microsoft.AspNet.Server.WebListener { diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 3d37438cbb..8a95f53a9e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -2,12 +2,9 @@ "version": "1.0.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { - "Microsoft.AspNet.FeatureModel": "1.0.0-*", - "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Http.Interfaces": "1.0.0-*", "Microsoft.AspNet.Hosting.Server.Interfaces": "1.0.0-*", - "Microsoft.Framework.ConfigurationModel.Interfaces": "1.0.0-*", - "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Framework.Logging.Interfaces": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*" }, "compilationOptions": { diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index ec9f673152..3aeedbfebd 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -2,7 +2,7 @@ "version": "1.0.0-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { - "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Framework.Logging.Interfaces": "1.0.0-*", "Microsoft.Net.WebSockets": "1.0.0-*" }, "compilationOptions": { From 0ad0fc6a9fb0ca43b8b8acac0c6b51ea58e7dcd0 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 9 Apr 2015 10:45:05 -0700 Subject: [PATCH 196/597] Remove logger dependencies. --- src/Microsoft.Net.Http.Server/LogHelper.cs | 27 +++++++++++++++++-- .../RequestProcessing/Request.cs | 15 ++++++++++- .../RequestProcessing/Response.cs | 13 ++++++++- src/Microsoft.Net.Http.Server/WebListener.cs | 2 +- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index 7413e56a70..a42ae0b0f3 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -23,7 +23,6 @@ using System; using System.Diagnostics; -using System.Globalization; using Microsoft.Framework.Logging; namespace Microsoft.Net.Http.Server @@ -34,7 +33,7 @@ namespace Microsoft.Net.Http.Server { if (factory == null) { - factory = new LoggerFactory(); + return new NullLogger(); } return factory.CreateLogger(type.FullName); @@ -87,5 +86,29 @@ namespace Microsoft.Net.Http.Server logger.LogError(location + "; " + message); } } + + private class NullLogger : ILogger + { + public IDisposable BeginScopeImpl(object state) + { + return new NullDispose(); + } + + public bool IsEnabled(LogLevel logLevel) + { + return false; + } + + public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func formatter) + { + } + + private class NullDispose : IDisposable + { + public void Dispose() + { + } + } + } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 37f604079d..1bd7e3c59f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -514,7 +514,7 @@ namespace Microsoft.Net.Http.Server } } - private class ReceiveRequestLogContext : ReflectionBasedLogValues + private class ReceiveRequestLogContext : ILogValues { private readonly Request _request; @@ -530,6 +530,19 @@ namespace Microsoft.Net.Http.Server public string Protocol { get { return "HTTP/" + _request.ProtocolVersion.ToString(2); } } public IEnumerable Headers { get { return new HeadersLogStructure(_request.Headers); } } + public IEnumerable> GetValues() + { + return new[] + { + new KeyValuePair("Method", Method), + new KeyValuePair("PathBase", PathBase), + new KeyValuePair("Path", Path), + new KeyValuePair("Query", Query), + new KeyValuePair("Protocol", Protocol), + new KeyValuePair("Headers", Headers), + }; + } + public override string ToString() { var requestBuilder = new StringBuilder("Received request: "); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index f4793e9e01..3d19df6781 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -883,7 +883,7 @@ namespace Microsoft.Net.Http.Server } } - private class SendResponseLogContext : ReflectionBasedLogValues + private class SendResponseLogContext : ILogValues { private readonly Response _response; @@ -897,6 +897,17 @@ namespace Microsoft.Net.Http.Server public string ReasonPhrase { get { return _response.ReasonPhrase ?? _response.GetReasonPhrase(_response.StatusCode); } } public IEnumerable Headers { get { return new HeadersLogStructure(_response.Headers); } } + public IEnumerable> GetValues() + { + return new[] + { + new KeyValuePair("Protocol", Protocol), + new KeyValuePair("StatusCode", StatusCode), + new KeyValuePair("ReasonPhrase", ReasonPhrase), + new KeyValuePair("Headers", Headers), + }; + } + public override string ToString() { // HTTP/1.1 200 OK diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 856a77fb69..727001dc81 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -91,7 +91,7 @@ namespace Microsoft.Net.Http.Server private long? _requestQueueLength; public WebListener() - : this(new LoggerFactory()) + : this(null) { } From e03c01506585f3951f02ecaa201e7960c68b7c0a Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 10 Apr 2015 10:40:09 -0700 Subject: [PATCH 197/597] Update IServerInformation namespace. --- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 1 - src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 0ee2f188c9..f5c87789c6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -37,7 +37,6 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Hosting.Server; using Microsoft.Framework.ConfigurationModel; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs index a6414b115a..3ad2fbb2f4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -16,7 +16,7 @@ // permissions and limitations under the License. using System.Reflection; -using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting.Server; namespace Microsoft.AspNet.Server.WebListener { From f191792b96ab5ca6b2e003eec8697c91a78ec081 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Wed, 15 Apr 2015 13:10:35 -0700 Subject: [PATCH 198/597] React to Http Challenge changes --- .../AuthenticationHandler.cs | 6 +++--- .../AuthenticationTests.cs | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index bbaa799bca..ed550f1074 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -79,11 +79,11 @@ namespace Microsoft.AspNet.Server.WebListener { var authScheme = scheme.ToString(); // Not including any auth types means it's a blanket challenge for any auth type. - if (context.AuthenticationSchemes == null || !context.AuthenticationSchemes.Any() - || context.AuthenticationSchemes.Contains(authScheme, StringComparer.Ordinal)) + if (context.AuthenticationScheme == null || + string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) { _customChallenges |= scheme; - context.Accept(authScheme, GetDescription(authScheme)); + context.Accept(); } } // A challenge was issued, it overrides any pre-set auth types. diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 451e9387af..f8a8c03947 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -353,7 +353,10 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - context.Response.Challenge(authTypeList); + foreach (var scheme in authTypeList) + { + context.Response.Challenge(scheme); + } return Task.FromResult(0); })) { From 1bb35041e9210535e0a2762c6549d29e58e48840 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 16 Apr 2015 12:32:18 -0700 Subject: [PATCH 199/597] Handle Http.Core rename. --- .../AuthenticationTests.cs | 2 +- .../HttpsTests.cs | 1 - .../OpaqueUpgradeTests.cs | 1 - .../RequestBodyTests.cs | 2 +- .../RequestHeaderTests.cs | 2 +- .../RequestTests.cs | 1 - .../ResponseBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 1 - .../ResponseSendFileTests.cs | 1 - .../ResponseTests.cs | 1 - .../ServerTests.cs | 1 - .../WebSocketTests.cs | 1 - .../project.json | 2 +- 13 files changed, 5 insertions(+), 13 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index f8a8c03947..d514a9f65c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -22,7 +22,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http.Core; +using Microsoft.AspNet.Http; using Microsoft.Net.Http.Server; using Xunit; using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 64a2b91072..b7c89ef1ad 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -23,7 +23,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Core; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 189cc35c90..162140a01c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -24,7 +24,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Testing.xunit; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 9763e76d33..b91951374c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -24,7 +24,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http.Core; +using Microsoft.AspNet.Http; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index ca104ef2c8..c5df794e2f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -21,7 +21,7 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http.Core; +using Microsoft.AspNet.Http; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index e87b8c0940..d0e502ad0c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -22,7 +22,6 @@ using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Core; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 2792b3bd35..e4cf7b4a33 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -23,7 +23,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http.Core; +using Microsoft.AspNet.Http; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 56cf7214ee..f6c887af11 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -22,7 +22,6 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Core; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 4da7f00ee9..76ae3e5a62 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -26,7 +26,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Core; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index 17ddeb7137..fe173fc13b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -21,7 +21,6 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Core; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 5a85157c6b..fc9fb62e83 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -26,7 +26,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Core; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index c486371ea0..b0f7c98e8f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -22,7 +22,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Testing.xunit; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 71d430dee6..310ae5d0f1 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -3,7 +3,7 @@ "test": "xunit.runner.aspnet" }, "dependencies": { - "Microsoft.AspNet.Http.Core": "1.0.0-*", + "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" From b0d0e94aba7c9d9a2394b16199412ab136caac3a Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 23 Apr 2015 16:06:18 -0700 Subject: [PATCH 200/597] Handle Authentication and WebSocket API changes. --- samples/SelfHostServer/Startup.cs | 4 ++-- .../AuthenticationHandler.cs | 12 ++++++------ .../FeatureContext.cs | 2 +- .../AuthenticationTests.cs | 16 ++++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index ce7464d85f..a2948987dc 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -21,10 +21,10 @@ namespace SelfHostServer app.Run(async context => { - if (context.IsWebSocketRequest) + if (context.WebSockets.IsWebSocketRequest) { byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); - WebSocket webSocket = await context.AcceptWebSocketAsync(); + WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); await webSocket.SendAsync(new ArraySegment(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None); await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Goodbye", CancellationToken.None); webSocket.Dispose(); diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index ed550f1074..4d65e87fda 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Server.WebListener _customChallenges = AuthenticationSchemes.None; } - public void Authenticate(IAuthenticateContext context) + public void Authenticate(AuthenticateContext context) { var user = _requestContext.User; var identity = user == null ? null : (ClaimsIdentity)user.Identity; @@ -67,13 +67,13 @@ namespace Microsoft.AspNet.Server.WebListener } } - public Task AuthenticateAsync(IAuthenticateContext context) + public Task AuthenticateAsync(AuthenticateContext context) { Authenticate(context); return Task.FromResult(0); } - public void Challenge(IChallengeContext context) + public void Challenge(ChallengeContext context) { foreach (var scheme in ListEnabledAuthSchemes()) { @@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Server.WebListener _requestContext.AuthenticationChallenges = _customChallenges; } - public void GetDescriptions(IDescribeSchemesContext context) + public void GetDescriptions(DescribeSchemesContext context) { // TODO: Caching, this data doesn't change per request. foreach (var scheme in ListEnabledAuthSchemes()) @@ -99,12 +99,12 @@ namespace Microsoft.AspNet.Server.WebListener } } - public void SignIn(ISignInContext context) + public void SignIn(SignInContext context) { // Not supported } - public void SignOut(ISignOutContext context) + public void SignOut(SignOutContext context) { // Not supported } diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index b2b0906caa..d3209b479b 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -410,7 +410,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - Task IHttpWebSocketFeature.AcceptAsync(IWebSocketAcceptContext context) + Task IHttpWebSocketFeature.AcceptAsync(WebSocketAcceptContext context) { // TODO: Advanced params string subProtocol = null; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index d514a9f65c..446bef3b9d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -201,7 +201,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); - var resultList = context.GetAuthenticationSchemes(); + var resultList = context.Authentication.GetAuthenticationSchemes(); if (authType == AuthenticationSchemes.AllowAnonymous) { Assert.Equal(0, resultList.Count()); @@ -236,7 +236,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); - var resultList = context.GetAuthenticationSchemes(); + var resultList = context.Authentication.GetAuthenticationSchemes(); Assert.Equal(4, resultList.Count()); return Task.FromResult(0); })) @@ -265,7 +265,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.False(context.User.Identity.IsAuthenticated); foreach (var scheme in authTypeList) { - var authResults = context.Authenticate(scheme); + var authResults = context.Authentication.Authenticate(scheme); Assert.Null(authResults); } return Task.FromResult(0); @@ -296,7 +296,7 @@ namespace Microsoft.AspNet.Server.WebListener var count = 0; foreach (var scheme in authTypeList) { - var authResults = context.Authenticate(scheme); + var authResults = context.Authentication.Authenticate(scheme); if (authResults != null) { count++; @@ -327,7 +327,7 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - context.Response.Challenge(); + context.Authentication.Challenge(); return Task.FromResult(0); })) { @@ -355,7 +355,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.False(context.User.Identity.IsAuthenticated); foreach (var scheme in authTypeList) { - context.Response.Challenge(scheme); + context.Authentication.Challenge(scheme); } return Task.FromResult(0); })) @@ -381,7 +381,7 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - context.Response.Challenge(authType.ToString()); + context.Authentication.Challenge(authType.ToString()); return Task.FromResult(0); })) { @@ -409,7 +409,7 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - Assert.Throws(() => context.Response.Challenge(authType.ToString())); + Assert.Throws(() => context.Authentication.Challenge(authType.ToString())); return Task.FromResult(0); })) { From 4d015760f669afd96f024bf6e114f4e942309897 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 27 Apr 2015 14:38:24 -0700 Subject: [PATCH 201/597] React to rename of IHttpClientCertificateFeature rename. --- .../FeatureContext.cs | 29 +++++++------------ .../RequestProcessing/Request.cs | 4 +-- .../HttpsTests.cs | 4 +-- .../HttpsTests.cs | 8 ++--- 4 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index d3209b479b..ed07ba6b5c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -37,7 +37,7 @@ namespace Microsoft.AspNet.Server.WebListener IHttpConnectionFeature, IHttpResponseFeature, IHttpSendFileFeature, - IHttpClientCertificateFeature, + ITlsConnectionFeature, IHttpRequestLifetimeFeature, IHttpWebSocketFeature, IHttpAuthenticationFeature, @@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Server.WebListener private int? _remotePort; private int? _localPort; private bool? _isLocal; - private X509Certificate _clientCert; + private X509Certificate2 _clientCert; private ClaimsPrincipal _user; private IAuthenticationHandler _authHandler; private Stream _responseStream; @@ -93,15 +93,16 @@ namespace Microsoft.AspNet.Server.WebListener { _features.Add(typeof(IHttpRequestFeature), this); _features.Add(typeof(IHttpConnectionFeature), this); - if (Request.IsSecureConnection) - { - // TODO: Should this feature be conditional? Should we add this for HTTP requests? - _features.Add(typeof(IHttpClientCertificateFeature), this); - } _features.Add(typeof(IHttpResponseFeature), this); _features.Add(typeof(IHttpSendFileFeature), this); _features.Add(typeof(IHttpRequestLifetimeFeature), this); _features.Add(typeof(IHttpAuthenticationFeature), this); + _features.Add(typeof(IRequestIdentifierFeature), this); + + if (Request.IsSecureConnection) + { + _features.Add(typeof(ITlsConnectionFeature), this); + } // Win8+ if (WebSocketHelpers.AreWebSocketsSupported) @@ -109,16 +110,6 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpUpgradeFeature), this); _features.Add(typeof(IHttpWebSocketFeature), this); } - - _features.Add(typeof(IRequestIdentifierFeature), this); - - // TODO: - /* - Server - _environment.Listener = _server; - Channel binding - _environment.ConnectionId = _request.ConnectionId; - */ } Stream IHttpRequestFeature.Body @@ -302,7 +293,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _remotePort = value; } } - X509Certificate IHttpClientCertificateFeature.ClientCertificate + X509Certificate2 ITlsConnectionFeature.ClientCertificate { get { @@ -315,7 +306,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _clientCert = value; } } - async Task IHttpClientCertificateFeature.GetClientCertificateAsync(CancellationToken cancellationToken) + async Task ITlsConnectionFeature.GetClientCertificateAsync(CancellationToken cancellationToken) { if (_clientCert == null) { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 1bd7e3c59f..9519037ca8 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -59,7 +59,7 @@ namespace Microsoft.Net.Http.Server private string _pathBase; private string _path; - private X509Certificate _clientCert; + private X509Certificate2 _clientCert; private HeaderCollection _headers; private BoundaryType _contentBoundaryType; @@ -430,7 +430,7 @@ namespace Microsoft.Net.Http.Server // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to // enable this, but it's unclear what Http.Sys would do. - public async Task GetClientCertificateAsync(CancellationToken cancellationToken = default(CancellationToken)) + public async Task GetClientCertificateAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (SslStatus == SslStatus.Insecure) { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index b7c89ef1ad..ec93a92eeb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var tls = httpContext.GetFeature(); + var tls = httpContext.GetFeature(); Assert.NotNull(tls); var cert = await tls.GetClientCertificateAsync(CancellationToken.None); Assert.Null(cert); @@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var tls = httpContext.GetFeature(); + var tls = httpContext.GetFeature(); Assert.NotNull(tls); var cert = await tls.GetClientCertificateAsync(CancellationToken.None); Assert.NotNull(cert); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index 4822827bd6..5483589211 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -90,16 +90,16 @@ namespace Microsoft.Net.Http.Server { using (var server = Utilities.CreateHttpsServer()) { - Task responseTask = SendRequestAsync(Address); + X509Certificate2 clientCert = FindClientCert(); + Assert.NotNull(clientCert); + Task responseTask = SendRequestAsync(Address, clientCert); var context = await server.GetContextAsync(); var cert = await context.Request.GetClientCertificateAsync(); Assert.NotNull(cert); context.Dispose(); - X509Certificate2 clientCert = FindClientCert(); - Assert.NotNull(clientCert); - string response = await SendRequestAsync(Address, clientCert); + string response = await responseTask; Assert.Equal(string.Empty, response); } } From 04570cd34f8f785196e3303ac4802c22d0284bf6 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 29 Apr 2015 15:33:15 -0700 Subject: [PATCH 202/597] React to Http.Interfaces package rename. --- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 8a95f53a9e..fccf0e9055 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -2,7 +2,7 @@ "version": "1.0.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { - "Microsoft.AspNet.Http.Interfaces": "1.0.0-*", + "Microsoft.AspNet.Http.Features": "1.0.0-*", "Microsoft.AspNet.Hosting.Server.Interfaces": "1.0.0-*", "Microsoft.Framework.Logging.Interfaces": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*" From 9fe183317e18742dce339005359370bc04901ea6 Mon Sep 17 00:00:00 2001 From: Brennan Date: Thu, 30 Apr 2015 09:05:53 -0700 Subject: [PATCH 203/597] React to Logging interface rename --- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index fccf0e9055..cda968aa70 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -4,7 +4,7 @@ "dependencies": { "Microsoft.AspNet.Http.Features": "1.0.0-*", "Microsoft.AspNet.Hosting.Server.Interfaces": "1.0.0-*", - "Microsoft.Framework.Logging.Interfaces": "1.0.0-*", + "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*" }, "compilationOptions": { diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 3aeedbfebd..664ee1f067 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -2,7 +2,7 @@ "version": "1.0.0-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { - "Microsoft.Framework.Logging.Interfaces": "1.0.0-*", + "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", "Microsoft.Net.WebSockets": "1.0.0-*" }, "compilationOptions": { From 2743c188528e91efdbba89685a97d4b8621dfc3f Mon Sep 17 00:00:00 2001 From: Brennan Date: Thu, 30 Apr 2015 10:00:22 -0700 Subject: [PATCH 204/597] React to Hosting interfaces rename --- src/Microsoft.AspNet.Server.WebListener/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index cda968aa70..4d2af603df 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -3,7 +3,7 @@ "description": "ASP.NET 5 self-host web server.", "dependencies": { "Microsoft.AspNet.Http.Features": "1.0.0-*", - "Microsoft.AspNet.Hosting.Server.Interfaces": "1.0.0-*", + "Microsoft.AspNet.Hosting.Server.Abstractions": "1.0.0-*", "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*" }, From d0276d4d55a642990b9e309dd2edb8853787e6c0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 7 May 2015 13:41:04 -0700 Subject: [PATCH 205/597] React to Http namespace changes. --- .../AuthenticationHandler.cs | 3 +-- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 4 ++-- .../AuthenticationTests.cs | 4 +--- .../HttpsTests.cs | 3 ++- .../OpaqueUpgradeTests.cs | 2 ++ .../RequestBodyTests.cs | 2 +- .../RequestHeaderTests.cs | 2 +- .../RequestTests.cs | 3 ++- .../ResponseBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 3 ++- .../ResponseSendFileTests.cs | 3 ++- .../ResponseTests.cs | 3 ++- .../ServerTests.cs | 1 + .../WebSocketTests.cs | 2 ++ 14 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index 4d65e87fda..5f0515d3ae 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -23,10 +23,9 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Authentication; +using Microsoft.AspNet.Http.Features.Authentication; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index ed07ba6b5c..e8a2120e20 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -25,8 +25,8 @@ using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Authentication; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Features.Authentication; using Microsoft.Net.Http.Server; using Microsoft.Net.WebSockets; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 446bef3b9d..cf0fb50a39 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -16,14 +16,12 @@ // permissions and limitations under the License. using System; -using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; -using Microsoft.Net.Http.Server; +using Microsoft.AspNet.Http.Internal; using Xunit; using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index ec93a92eeb..f7e1d5a3fa 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -22,7 +22,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 162140a01c..fccf18ba9a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -24,6 +24,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Testing.xunit; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index b91951374c..1684a888bc 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -24,7 +24,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index c5df794e2f..01a9e12b98 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -21,7 +21,7 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index d0e502ad0c..bb005a0e22 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -21,7 +21,8 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index e4cf7b4a33..38d91a330a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -23,7 +23,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index f6c887af11..bf73c78f94 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -21,7 +21,8 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 76ae3e5a62..58fbf286b5 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -25,7 +25,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index fe173fc13b..eaafe14c21 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -20,7 +20,8 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; -using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index fc9fb62e83..f35353c52b 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -26,6 +26,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Internal; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index b0f7c98e8f..544ef17a22 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -22,6 +22,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Testing.xunit; using Xunit; From 57594803fce3c1708e48d35bfc98a104ec6c1d7a Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 12 May 2015 11:34:21 -0700 Subject: [PATCH 206/597] React to IHttpRequestLifetimeFeature change. --- .../FeatureContext.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index e8a2120e20..4d42a0db5e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -63,6 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener private X509Certificate2 _clientCert; private ClaimsPrincipal _user; private IAuthenticationHandler _authHandler; + private CancellationToken? _disconnectToken; private Stream _responseStream; private IDictionary _responseHeaders; @@ -375,7 +376,15 @@ namespace Microsoft.AspNet.Server.WebListener CancellationToken IHttpRequestLifetimeFeature.RequestAborted { - get { return _requestContext.DisconnectToken; } + get + { + if (!_disconnectToken.HasValue) + { + _disconnectToken = _requestContext.DisconnectToken; + } + return _disconnectToken.Value; + } + set { _disconnectToken = value; } } void IHttpRequestLifetimeFeature.Abort() From a1422fa51b57b3494655fe85b6d4af18a918215c Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 12 May 2015 14:15:20 -0700 Subject: [PATCH 207/597] Update project.json in test --- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index f2f6f8caee..d5a72c4598 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -9,7 +9,7 @@ }, "frameworks": { "dnx451": { - frameworkAssemblies: { + "frameworkAssemblies": { "System.Net.Http": "", "System.Net.Http.WebRequest": "" } From 913e407b5ad63421cec35d43ecc553a7f8754f5b Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 15 May 2015 11:27:29 -0700 Subject: [PATCH 208/597] React to CoreClr dependency changes. --- .../project.json | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 4d2af603df..d035af3107 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -1,17 +1,21 @@ { - "version": "1.0.0-*", - "description": "ASP.NET 5 self-host web server.", - "dependencies": { - "Microsoft.AspNet.Http.Features": "1.0.0-*", - "Microsoft.AspNet.Hosting.Server.Abstractions": "1.0.0-*", - "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", - "Microsoft.Net.Http.Server": "1.0.0-*" - }, - "compilationOptions": { - "allowUnsafe": true - }, - "frameworks": { - "dnx451": { }, - "dnxcore50": { } + "version": "1.0.0-*", + "description": "ASP.NET 5 self-host web server.", + "dependencies": { + "Microsoft.AspNet.Http.Features": "1.0.0-*", + "Microsoft.AspNet.Hosting.Server.Abstractions": "1.0.0-*", + "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", + "Microsoft.Net.Http.Server": "1.0.0-*" + }, + "compilationOptions": { + "allowUnsafe": true + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { + "dependencies": { + "System.Security.Claims": "4.0.0-beta-*" + } } + } } From 748a6e109029d7b9f53e992e92189d0c6ae38935 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 15 May 2015 11:31:49 -0700 Subject: [PATCH 209/597] React to CoreClr dependency changes. --- src/Microsoft.Net.Http.Server/project.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 664ee1f067..5e7160e13d 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -16,8 +16,10 @@ "Microsoft.Win32.Primitives": "4.0.0-beta-*", "System.Diagnostics.Debug": "4.0.10-beta-*", "System.IO.FileSystem": "4.0.0-beta-*", + "System.Security.Claims": "4.0.0-beta-*", "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", - "System.Security.Principal.Windows": "4.0.0-beta-*" + "System.Security.Principal.Windows": "4.0.0-beta-*", + "System.Threading.Overlapped": "4.0.0-beta-*" } } } From 2681e8b3d138eb23f5c5aa8d1cdfb0dc6b895642 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 15 May 2015 14:55:54 -0700 Subject: [PATCH 210/597] #112, #113 Sort out default response modes, allow manual chunking. --- src/Microsoft.Net.Http.Server/Constants.cs | 3 + .../RequestProcessing/BoundaryType.cs | 4 +- .../RequestProcessing/Request.cs | 7 +- .../RequestProcessing/Response.cs | 198 +++++--------- .../RequestProcessing/ResponseStream.cs | 11 +- .../ResponseBodyTests.cs | 23 +- .../ResponseHeaderTests.cs | 53 +--- .../ResponseSendFileTests.cs | 14 +- .../ResponseBodyTests.cs | 51 ++-- .../ResponseHeaderTests.cs | 251 ++++++++++++++---- .../ResponseSendFileTests.cs | 14 +- 11 files changed, 320 insertions(+), 309 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/Constants.cs b/src/Microsoft.Net.Http.Server/Constants.cs index e3336f6bea..4991637282 100644 --- a/src/Microsoft.Net.Http.Server/Constants.cs +++ b/src/Microsoft.Net.Http.Server/Constants.cs @@ -29,6 +29,9 @@ namespace Microsoft.Net.Http.Server { internal const string HttpScheme = "http"; internal const string HttpsScheme = "https"; + internal const string Chunked = "chunked"; + internal const string Close = "close"; + internal const string Zero = "0"; internal const string SchemeDelimiter = "://"; internal static Version V1_0 = new Version(1, 0); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs index b45b24b658..f2b4e78568 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs @@ -28,6 +28,8 @@ namespace Microsoft.Net.Http.Server None = 0, Chunked = 1, // Transfer-Encoding: chunked ContentLength = 2, // Content-Length: XXX - Invalid = 3, + Close = 3, // Connection: close + PassThrough = 4, // The application is handling the boundary themselves (e.g. chunking themselves). + Invalid = 5, } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 9519037ca8..668cc6dfea 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -263,6 +263,11 @@ namespace Microsoft.Net.Http.Server get { return _httpMethod; } } + public bool IsHeadMethod + { + get { return string.Equals(_httpMethod, "HEAD", StringComparison.OrdinalIgnoreCase); } + } + public Stream Body { get @@ -413,7 +418,7 @@ namespace Microsoft.Net.Http.Server { get { - return Headers.Get(HttpKnownHeaderNames.ContentLength); + return Headers.Get(HttpKnownHeaderNames.ContentType); } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 3d19df6781..d0cf0c98a7 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -38,13 +38,13 @@ namespace Microsoft.Net.Http.Server { public sealed unsafe class Response { - private static readonly string[] ZeroContentLength = new[] { "0" }; + private static readonly string[] ZeroContentLength = new[] { Constants.Zero }; private ResponseState _responseState; private HeaderCollection _headers; private string _reasonPhrase; private ResponseStream _nativeStream; - private long _contentLength; + private long _expectedBodyLength; private BoundaryType _boundaryType; private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 _nativeResponse; private IList, object>> _onSendingHeadersActions; @@ -166,11 +166,11 @@ namespace Microsoft.Net.Http.Server get { return _headers; } } - internal long CalculatedLength + internal long ExpectedBodyLength { get { - return _contentLength; + return _expectedBodyLength; } } @@ -184,7 +184,7 @@ namespace Microsoft.Net.Http.Server if (!string.IsNullOrWhiteSpace(contentLengthString)) { contentLengthString = contentLengthString.Trim(); - if (string.Equals("0", contentLengthString, StringComparison.Ordinal)) + if (string.Equals(Constants.Zero, contentLengthString, StringComparison.Ordinal)) { return 0; } @@ -225,7 +225,7 @@ namespace Microsoft.Net.Http.Server { get { - return Headers.Get(HttpKnownHeaderNames.ContentLength); + return Headers.Get(HttpKnownHeaderNames.ContentType); } set { @@ -241,44 +241,6 @@ namespace Microsoft.Net.Http.Server } } - private Version GetProtocolVersion() - { - /* - Version requestVersion = Request.ProtocolVersion; - Version responseVersion = requestVersion; - string protocolVersion = RequestContext.Environment.Get(Constants.HttpResponseProtocolKey); - - // Optional - if (!string.IsNullOrWhiteSpace(protocolVersion)) - { - if (string.Equals("HTTP/1.1", protocolVersion, StringComparison.OrdinalIgnoreCase)) - { - responseVersion = Constants.V1_1; - } - if (string.Equals("HTTP/1.0", protocolVersion, StringComparison.OrdinalIgnoreCase)) - { - responseVersion = Constants.V1_0; - } - else - { - // TODO: Just log? It's too late to get this to user code. - throw new ArgumentException(string.Empty, Constants.HttpResponseProtocolKey); - } - } - - if (requestVersion == responseVersion) - { - return requestVersion; - } - - // Return the lesser of the two versions. There are only two, so it it will always be 1.0. - return Constants.V1_0;*/ - - // TODO: IHttpResponseInformation does not define a response protocol version. Http.Sys doesn't let - // us send anything but 1.1 anyways, but we could at least use it to set things like the connection header. - return Request.ProtocolVersion; - } - // should only be called from RequestContext internal void Dispose() { @@ -476,121 +438,87 @@ namespace Microsoft.Net.Http.Server RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(RequestContext); } - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + var flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; Debug.Assert(!ComputedHeaders, "HttpListenerResponse::ComputeHeaders()|ComputedHeaders is true."); _responseState = ResponseState.ComputedHeaders; - /* - // here we would check for BoundaryType.Raw, in this case we wouldn't need to do anything - if (m_BoundaryType==BoundaryType.Raw) { - return flags; - } - */ - // Check the response headers to determine the correct keep alive and boundary type. - Version responseVersion = GetProtocolVersion(); - _nativeResponse.Response_V1.Version.MajorVersion = (ushort)responseVersion.Major; - _nativeResponse.Response_V1.Version.MinorVersion = (ushort)responseVersion.Minor; - bool keepAlive = responseVersion >= Constants.V1_1; - string connectionString = Headers.Get(HttpKnownHeaderNames.Connection); - string keepAliveString = Headers.Get(HttpKnownHeaderNames.KeepAlive); - bool closeSet = false; - bool keepAliveSet = false; + // Gather everything from the request that affects the response: + var requestVersion = Request.ProtocolVersion; + var requestConnectionString = Request.Headers.Get(HttpKnownHeaderNames.Connection); + var isHeadRequest = Request.IsHeadMethod; + var requestCloseSet = Matches(Constants.Close, requestConnectionString); - if (!string.IsNullOrWhiteSpace(connectionString) && string.Equals("close", connectionString.Trim(), StringComparison.OrdinalIgnoreCase)) + // Gather everything the app may have set on the response: + // Http.Sys does not allow us to specify the response protocol version, assume this is a HTTP/1.1 response when making decisions. + var responseConnectionString = Headers.Get(HttpKnownHeaderNames.Connection); + var transferEncodingString = Headers.Get(HttpKnownHeaderNames.TransferEncoding); + var responseContentLength = ContentLength; + var responseCloseSet = Matches(Constants.Close, responseConnectionString); + var responseChunkedSet = Matches(Constants.Chunked, transferEncodingString); + var statusCanHaveBody = CanSendResponseBody(_requestContext.Response.StatusCode); + + // Determine if the connection will be kept alive or closed. + var keepConnectionAlive = true; + if (requestVersion <= Constants.V1_0 // Http.Sys does not support "Keep-Alive: true" or "Connection: Keep-Alive" + || (requestVersion == Constants.V1_1 && requestCloseSet) + || responseCloseSet) { - keepAlive = false; - closeSet = true; - } - else if (!string.IsNullOrWhiteSpace(keepAliveString) && string.Equals("true", keepAliveString.Trim(), StringComparison.OrdinalIgnoreCase)) - { - keepAlive = true; - keepAliveSet = true; + keepConnectionAlive = false; } - // Content-Length takes priority - long? contentLength = ContentLength; - string transferEncodingString = Headers.Get(HttpKnownHeaderNames.TransferEncoding); - - if (responseVersion == Constants.V1_0 && !string.IsNullOrEmpty(transferEncodingString) - && string.Equals("chunked", transferEncodingString.Trim(), StringComparison.OrdinalIgnoreCase)) + // Determine the body format. If the user asks to do something, let them, otherwise choose a good default for the scenario. + if (responseContentLength.HasValue) { - // A 1.0 client can't process chunked responses. - Headers.Remove(HttpKnownHeaderNames.TransferEncoding); - transferEncodingString = null; - } - - if (contentLength.HasValue) - { - _contentLength = contentLength.Value; _boundaryType = BoundaryType.ContentLength; - if (_contentLength == 0) - { - flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; - } + // ComputeLeftToWrite checks for HEAD requests when setting _leftToWrite + _expectedBodyLength = responseContentLength.Value; } - else if (!string.IsNullOrWhiteSpace(transferEncodingString) - && string.Equals("chunked", transferEncodingString.Trim(), StringComparison.OrdinalIgnoreCase)) + else if (responseChunkedSet) + { + // The application is performing it's own chunking. + _boundaryType = BoundaryType.PassThrough; + } + else if (endOfRequest && !(isHeadRequest && statusCanHaveBody)) // HEAD requests always end without a body. Assume a GET response would have a body. + { + if (statusCanHaveBody) + { + Headers[HttpKnownHeaderNames.ContentLength] = Constants.Zero; + } + _boundaryType = BoundaryType.ContentLength; + _expectedBodyLength = 0; + } + else if (keepConnectionAlive && requestVersion == Constants.V1_1) { - // Then Transfer-Encoding: chunked _boundaryType = BoundaryType.Chunked; - } - else if (endOfRequest) - { - // The request is ending without a body, add a Content-Length: 0 header. - Headers[HttpKnownHeaderNames.ContentLength] = "0"; - _boundaryType = BoundaryType.ContentLength; - _contentLength = 0; - flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + Headers[HttpKnownHeaderNames.TransferEncoding] = Constants.Chunked; } else { - // Then fall back to Connection:Close transparent mode. - _boundaryType = BoundaryType.None; - flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; // seems like HTTP_SEND_RESPONSE_FLAG_MORE_DATA but this hangs the app; - if (responseVersion == Constants.V1_0) - { - keepAlive = false; - } - else - { - Headers[HttpKnownHeaderNames.TransferEncoding] = "chunked"; - _boundaryType = BoundaryType.Chunked; - } - - if (CanSendResponseBody(_requestContext.Response.StatusCode)) - { - _contentLength = -1; - } - else - { - Headers[HttpKnownHeaderNames.ContentLength] = "0"; - _contentLength = 0; - _boundaryType = BoundaryType.ContentLength; - } + // The length cannot be determined, so we must close the connection + keepConnectionAlive = false; + _boundaryType = BoundaryType.Close; } - // Also, Keep-Alive vs Connection Close - if (!keepAlive) + // Managed connection lifetime + if (!keepConnectionAlive) { - if (!closeSet) + // All Http.Sys responses are v1.1, so use 1.1 response headers + // Note that if we don't add this header, Http.Sys will often do it for us. + if (!responseCloseSet) { - Headers.Append(HttpKnownHeaderNames.Connection, "close"); - } - if (flags == UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE) - { - flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; - } - } - else - { - if (Request.ProtocolVersion.Minor == 0 && !keepAliveSet) - { - Headers[HttpKnownHeaderNames.KeepAlive] = "true"; + Headers.Append(HttpKnownHeaderNames.Connection, Constants.Close); } + flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } + return flags; } + private static bool Matches(string knownValue, string input) + { + return string.Equals(knownValue, input?.Trim(), StringComparison.OrdinalIgnoreCase); + } + private List SerializeHeaders(bool isOpaqueUpgrade) { Headers.Sent = true; // Prohibit further modifications. diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index feec8feb6f..2ce897c414 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -231,7 +231,7 @@ namespace Microsoft.Net.Http.Server } else if (_requestContext.Response.BoundaryType == BoundaryType.ContentLength) { - _leftToWrite = _requestContext.Response.CalculatedLength; + _leftToWrite = _requestContext.Response.ExpectedBodyLength; } else { @@ -764,7 +764,7 @@ namespace Microsoft.Net.Http.Server if (_leftToWrite > 0 && !_inOpaqueMode) { _requestContext.Abort(); - // TODO: Reduce this to a logged warning, it is thrown too late to be visible in user code. + // This is logged rather than thrown because it is too late for an exception to be visible in user code. LogHelper.LogError(_requestContext.Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length."); return; } @@ -775,9 +775,12 @@ namespace Microsoft.Net.Http.Server } uint statusCode = 0; - if ((_requestContext.Response.BoundaryType == BoundaryType.Chunked || _requestContext.Response.BoundaryType == BoundaryType.None) && (String.Compare(_requestContext.Request.Method, "HEAD", StringComparison.OrdinalIgnoreCase) != 0)) + if ((_requestContext.Response.BoundaryType == BoundaryType.Chunked + || _requestContext.Response.BoundaryType == BoundaryType.Close + || _requestContext.Response.BoundaryType == BoundaryType.PassThrough) + && !_requestContext.Request.IsHeadMethod) { - if (_requestContext.Response.BoundaryType == BoundaryType.None) + if (_requestContext.Response.BoundaryType == BoundaryType.Close) { flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 38d91a330a..7f77ff1880 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -99,28 +99,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); } } - /* TODO: response protocol - [Fact] - public async Task ResponseBody_Http10WriteNoHeaders_DefaultsConnectionClose() - { - string address; - using (Utilities.CreateHttpServer(out address, env => - { - env["owin.ResponseProtocol"] = "HTTP/1.0"; - env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); - return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); - })) - { - HttpResponseMessage response = await SendRequestAsync(address); - Assert.Equal(200, (int)response.StatusCode); - Assert.Equal(new Version(1, 1), response.Version); // Http.Sys won't transmit 1.0 - IEnumerable ignored; - Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); - Assert.Null(response.Headers.TransferEncodingChunked); - Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); - } - } - */ + [Fact] public async Task ResponseBody_WriteContentLengthNoneWritten_Throws() { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index bf73c78f94..5d7cc5234a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -16,9 +16,11 @@ // permissions and limitations under the License. using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Features; @@ -134,6 +136,7 @@ namespace Microsoft.AspNet.Server.WebListener var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders["Connection"] = new string[] { "Close" }; + httpContext.Response.Body.Flush(); // Http.Sys adds the Content-Length: header for us if we don't flush return Task.FromResult(0); })) { @@ -141,47 +144,12 @@ namespace Microsoft.AspNet.Server.WebListener response.EnsureSuccessStatusCode(); Assert.True(response.Headers.ConnectionClose.Value); Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); - } - } - /* TODO: - [Fact] - public async Task ResponseHeaders_SendsHttp10_Gets11Close() - { - string address; - using (Utilities.CreateHttpServer(out address, env => - { - env["owin.ResponseProtocol"] = "HTTP/1.0"; - return Task.FromResult(0); - })) - { - HttpResponseMessage response = await SendRequestAsync(address); - response.EnsureSuccessStatusCode(); - Assert.Equal(new Version(1, 1), response.Version); - Assert.True(response.Headers.ConnectionClose.Value); - Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); - } - } - - [Fact] - public async Task ResponseHeaders_SendsHttp10WithBody_Gets11Close() - { - string address; - using (Utilities.CreateHttpServer(out address, env => - { - env["owin.ResponseProtocol"] = "HTTP/1.0"; - return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); - })) - { - HttpResponseMessage response = await SendRequestAsync(address); - response.EnsureSuccessStatusCode(); - Assert.Equal(new Version(1, 1), response.Version); Assert.False(response.Headers.TransferEncodingChunked.HasValue); - Assert.False(response.Content.Headers.Contains("Content-Length")); - Assert.True(response.Headers.ConnectionClose.Value); - Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + IEnumerable values; + var result = response.Content.Headers.TryGetValues("Content-Length", out values); + Assert.False(result); } } - */ [Fact] public async Task ResponseHeaders_HTTP10Request_Gets11Close() @@ -201,12 +169,13 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(new Version(1, 1), response.Version); Assert.True(response.Headers.ConnectionClose.Value); Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); } } } [Fact] - public async Task ResponseHeaders_HTTP10Request_RemovesChunkedHeader() + public async Task ResponseHeaders_HTTP10RequestWithChunkedHeader_ManualChunking() { string address; using (Utilities.CreateHttpServer(out address, env => @@ -215,7 +184,8 @@ namespace Microsoft.AspNet.Server.WebListener var responseInfo = httpContext.GetFeature(); var responseHeaders = responseInfo.Headers; responseHeaders["Transfer-Encoding"] = new string[] { "chunked" }; - return responseInfo.Body.WriteAsync(new byte[10], 0, 10); + var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); + return responseInfo.Body.WriteAsync(responseBytes, 0, responseBytes.Length); })) { using (HttpClient client = new HttpClient()) @@ -225,10 +195,11 @@ namespace Microsoft.AspNet.Server.WebListener HttpResponseMessage response = await client.SendAsync(request); response.EnsureSuccessStatusCode(); Assert.Equal(new Version(1, 1), response.Version); - Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.TransferEncodingChunked.HasValue); Assert.False(response.Content.Headers.Contains("Content-Length")); Assert.True(response.Headers.ConnectionClose.Value); Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + Assert.Equal("Manually Chunked", await response.Content.ReadAsStringAsync()); } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 58fbf286b5..4814537415 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -162,14 +162,13 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task ResponseSendFile_Chunked_Chunked() + public async Task ResponseSendFile_Unspecified_Chunked() { string address; using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); - httpContext.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { @@ -183,14 +182,13 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task ResponseSendFile_MultipleChunks_Chunked() + public async Task ResponseSendFile_MultipleWrites_Chunked() { string address; using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.GetFeature(); - httpContext.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None).Wait(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) @@ -205,7 +203,7 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task ResponseSendFile_ChunkedHalfOfFile_Chunked() + public async Task ResponseSendFile_HalfOfFile_Chunked() { string address; using (Utilities.CreateHttpServer(out address, env => @@ -225,7 +223,7 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task ResponseSendFile_ChunkedOffsetOutOfRange_Throws() + public async Task ResponseSendFile_OffsetOutOfRange_Throws() { string address; using (Utilities.CreateHttpServer(out address, env => @@ -241,7 +239,7 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task ResponseSendFile_ChunkedCountOutOfRange_Throws() + public async Task ResponseSendFile_CountOutOfRange_Throws() { string address; using (Utilities.CreateHttpServer(out address, env => @@ -257,7 +255,7 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public async Task ResponseSendFile_ChunkedCount0_Chunked() + public async Task ResponseSendFile_Count0_Chunked() { string address; using (Utilities.CreateHttpServer(out address, env => diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index b76bda6db0..779b7080fb 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; +using System.Text; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -37,7 +38,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseBody_WriteChunked_Chunked() + public async Task ResponseBody_WriteChunked_ManuallyChunked() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -45,11 +46,10 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); - context.Request.Headers["transfeR-Encoding"] = " CHunked "; + context.Response.Headers["transfeR-Encoding"] = " CHunked "; Stream stream = context.Response.Body; - stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); - stream.Write(new byte[10], 0, 10); - await stream.WriteAsync(new byte[10], 0, 10); + var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); + await stream.WriteAsync(responseBytes, 0, responseBytes.Length); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -58,7 +58,7 @@ namespace Microsoft.Net.Http.Server IEnumerable ignored; Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); - Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); + Assert.Equal("Manually Chunked", await response.Content.ReadAsStringAsync()); } } @@ -88,43 +88,28 @@ namespace Microsoft.Net.Http.Server Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); } } - /* TODO: response protocol + [Fact] - public async Task ResponseBody_Http10WriteNoHeaders_DefaultsConnectionClose() + public async Task ResponseBody_WriteContentLengthNoneWritten_Aborts() { - using (Utilities.CreateHttpServer(env => + string address; + using (var server = Utilities.CreateHttpServer(out address)) { - env["owin.ResponseProtocol"] = "HTTP/1.0"; - env.Get("owin.ResponseBody").Write(new byte[10], 0, 10); - return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); - })) - { - HttpResponseMessage response = await SendRequestAsync(Address); - Assert.Equal(200, (int)response.StatusCode); - Assert.Equal(new Version(1, 1), response.Version); // Http.Sys won't transmit 1.0 - IEnumerable ignored; - Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); - Assert.Null(response.Headers.TransferEncodingChunked); - Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); - } - } - */ - /* TODO: Why does this test time out? - [Fact] - public async Task ResponseBody_WriteContentLengthNoneWritten_Throws() - { - using (var server = Utilities.CreateHttpServer()) - { - Task responseTask = SendRequestAsync(Address); + Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); - context.Response.Headers["Content-lenGth"] = new[] { " 20 " }; + context.Response.Headers["Content-lenGth"] = " 20 "; + context.Dispose(); + + // HttpClient retries the request because it didn't get a response. + context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); await Assert.ThrowsAsync(() => responseTask); } } - */ + [Fact] public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Throws() { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index 2fc83a613e..f16bc98142 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using System.Net; using System.Net.Http; +using System.Text; using System.Threading.Tasks; using Xunit; @@ -12,7 +13,7 @@ namespace Microsoft.Net.Http.Server public class ResponseHeaderTests { [Fact] - public async Task ResponseHeaders_ServerSendsDefaultHeaders_Success() + public async Task ResponseHeaders_11Request_ServerSendsDefaultHeaders() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -33,6 +34,143 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task ResponseHeaders_10Request_ServerSendsDefaultHeaders() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address, usehttp11: false); + + var context = await server.GetContextAsync(); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(3, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.Equal(1, response.Content.Headers.Count()); + Assert.Equal(0, response.Content.Headers.ContentLength); + } + } + + [Fact] + public async Task ResponseHeaders_11HeadRequest_ServerSendsDefaultHeaders() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendHeadRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(3, response.Headers.Count()); + Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.False(response.Content.Headers.Contains("Content-Length")); + Assert.Equal(0, response.Content.Headers.Count()); + } + } + + [Fact] + public async Task ResponseHeaders_10HeadRequest_ServerSendsDefaultHeaders() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendHeadRequestAsync(address, usehttp11: false); + + var context = await server.GetContextAsync(); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(3, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.False(response.Content.Headers.Contains("Content-Length")); + Assert.Equal(0, response.Content.Headers.Count()); + } + } + + [Fact] + public async Task ResponseHeaders_11HeadRequestWithContentLength_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendHeadRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.ContentLength = 20; + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(2, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.Equal(1, response.Content.Headers.Count()); + Assert.Equal(20, response.Content.Headers.ContentLength); + } + } + + [Fact] + public async Task ResponseHeaders_11RequestStatusCodeWithoutBody_NoContentLengthOrChunkedOrClose() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = 204; // No Content + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(2, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.False(response.Content.Headers.Contains("Content-Length")); + Assert.Equal(0, response.Content.Headers.Count()); + } + } + + [Fact] + public async Task ResponseHeaders_11HeadRequestStatusCodeWithoutBody_NoContentLengthOrChunkedOrClose() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendHeadRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = 204; // No Content + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(2, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.Date.HasValue); + Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); + Assert.False(response.Content.Headers.Contains("Content-Length")); + Assert.Equal(0, response.Content.Headers.Count()); + } + } + [Fact] public async Task ResponseHeaders_ServerSendsSingleValueKnownHeaders_Success() { @@ -127,43 +265,6 @@ namespace Microsoft.Net.Http.Server Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); } } - /* TODO: - [Fact] - public async Task ResponseHeaders_SendsHttp10_Gets11Close() - { - using (Utilities.CreateHttpServer(env => - { - env["owin.ResponseProtocol"] = "HTTP/1.0"; - return Task.FromResult(0); - })) - { - HttpResponseMessage response = await SendRequestAsync(Address); - response.EnsureSuccessStatusCode(); - Assert.Equal(new Version(1, 1), response.Version); - Assert.True(response.Headers.ConnectionClose.Value); - Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); - } - } - - [Fact] - public async Task ResponseHeaders_SendsHttp10WithBody_Gets11Close() - { - using (Utilities.CreateHttpServer(env => - { - env["owin.ResponseProtocol"] = "HTTP/1.0"; - return env.Get("owin.ResponseBody").WriteAsync(new byte[10], 0, 10); - })) - { - HttpResponseMessage response = await SendRequestAsync(Address); - response.EnsureSuccessStatusCode(); - Assert.Equal(new Version(1, 1), response.Version); - Assert.False(response.Headers.TransferEncodingChunked.HasValue); - Assert.False(response.Content.Headers.Contains("Content-Length")); - Assert.True(response.Headers.ConnectionClose.Value); - Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); - } - } - */ [Fact] public async Task ResponseHeaders_HTTP10Request_Gets11Close() @@ -171,26 +272,21 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - using (HttpClient client = new HttpClient()) - { - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, address); - request.Version = new Version(1, 0); - Task responseTask = client.SendAsync(request); + Task responseTask = SendRequestAsync(address, usehttp11: false); - var context = await server.GetContextAsync(); - context.Dispose(); + var context = await server.GetContextAsync(); + context.Dispose(); - HttpResponseMessage response = await responseTask; - response.EnsureSuccessStatusCode(); - Assert.Equal(new Version(1, 1), response.Version); - Assert.True(response.Headers.ConnectionClose.Value); - Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); - } + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(response.Headers.ConnectionClose.Value); + Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); } } [Fact] - public async Task ResponseHeaders_HTTP10Request_RemovesChunkedHeader() + public async Task ResponseHeaders_HTTP10Request_AllowsManualChunking() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -204,20 +300,41 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; responseHeaders["Transfer-Encoding"] = "chunked"; - await context.Response.Body.WriteAsync(new byte[10], 0, 10); + var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); + await context.Response.Body.WriteAsync(responseBytes, 0, responseBytes.Length); context.Dispose(); HttpResponseMessage response = await responseTask; response.EnsureSuccessStatusCode(); Assert.Equal(new Version(1, 1), response.Version); - Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.TransferEncodingChunked.Value); Assert.False(response.Content.Headers.Contains("Content-Length")); Assert.True(response.Headers.ConnectionClose.Value); Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); + Assert.Equal("Manually Chunked", await response.Content.ReadAsStringAsync()); } } } + [Fact] + public async Task ResponseHeaders_HTTP10KeepAliveRequest_Gets11Close() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + // Http.Sys does not support 1.0 keep-alives. + Task responseTask = SendRequestAsync(address, usehttp11: false, sendKeepAlive: true); + + var context = await server.GetContextAsync(); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(response.Headers.ConnectionClose.Value); + } + } + [Fact] public async Task Headers_FlushSendsHeaders_Success() { @@ -290,11 +407,33 @@ namespace Microsoft.Net.Http.Server } } - private async Task SendRequestAsync(string uri) + private async Task SendRequestAsync(string uri, bool usehttp11 = true, bool sendKeepAlive = false) { using (HttpClient client = new HttpClient()) { - return await client.GetAsync(uri); + var request = new HttpRequestMessage(HttpMethod.Get, uri); + if (!usehttp11) + { + request.Version = new Version(1, 0); + } + if (sendKeepAlive) + { + request.Headers.Add("Connection", "Keep-Alive"); + } + return await client.SendAsync(request); + } + } + + private async Task SendHeadRequestAsync(string uri, bool usehttp11 = true) + { + using (HttpClient client = new HttpClient()) + { + var request = new HttpRequestMessage(HttpMethod.Head, uri); + if (!usehttp11) + { + request.Version = new Version(1, 0); + } + return await client.SendAsync(request); } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index f13af46cf1..b81fd6d514 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -84,7 +84,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseSendFile_Chunked_Chunked() + public async Task ResponseSendFile_Unspecified_Chunked() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -92,7 +92,6 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); - context.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -106,7 +105,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseSendFile_MultipleChunks_Chunked() + public async Task ResponseSendFile_MultipleWrites_Chunked() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -114,7 +113,6 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); - context.Response.Headers["Transfer-EncodinG"] = "CHUNKED"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -129,7 +127,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseSendFile_ChunkedHalfOfFile_Chunked() + public async Task ResponseSendFile_HalfOfFile_Chunked() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -150,7 +148,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseSendFile_ChunkedOffsetOutOfRange_Throws() + public async Task ResponseSendFile_OffsetOutOfRange_Throws() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -167,7 +165,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseSendFile_ChunkedCountOutOfRange_Throws() + public async Task ResponseSendFile_CountOutOfRange_Throws() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -184,7 +182,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseSendFile_ChunkedCount0_Chunked() + public async Task ResponseSendFile_Count0_Chunked() { string address; using (var server = Utilities.CreateHttpServer(out address)) From 179bdbf903e130eec9cf91e89a4614dec60a922e Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 18 May 2015 11:44:45 -0700 Subject: [PATCH 211/597] #82 Implement ITlsTokenBindingFeature. --- .../FeatureContext.cs | 12 +++ .../AuthenticationManager.cs | 16 +-- .../NativeInterop/HeapAllocHandle.cs | 39 +++++++ .../NativeInterop/TokenBindingUtil.cs | 94 ++++++++++++++++ .../NativeInterop/UnsafeNativeMethods.cs | 102 +++++++++++++++++- .../RequestProcessing/Request.cs | 40 ++++++- 6 files changed, 294 insertions(+), 9 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs create mode 100644 src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 4d42a0db5e..18a0c9c9c9 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -38,6 +38,7 @@ namespace Microsoft.AspNet.Server.WebListener IHttpResponseFeature, IHttpSendFileFeature, ITlsConnectionFeature, + ITlsTokenBindingFeature, IHttpRequestLifetimeFeature, IHttpWebSocketFeature, IHttpAuthenticationFeature, @@ -103,6 +104,7 @@ namespace Microsoft.AspNet.Server.WebListener if (Request.IsSecureConnection) { _features.Add(typeof(ITlsConnectionFeature), this); + _features.Add(typeof(ITlsTokenBindingFeature), this); } // Win8+ @@ -316,6 +318,16 @@ namespace Microsoft.AspNet.Server.WebListener return _clientCert; } + byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId() + { + return Request.GetProvidedTokenBindingId(); + } + + byte[] ITlsTokenBindingFeature.GetReferredTokenBindingId() + { + return Request.GetReferredTokenBindingId(); + } + Stream IHttpResponseFeature.Body { get diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index d0a43e5dd1..ea67513993 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -167,14 +167,18 @@ namespace Microsoft.Net.Http.Server return false; } - internal static unsafe ClaimsPrincipal GetUser(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* requestInfo) + internal static unsafe ClaimsPrincipal GetUser(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* requestInfo, int infoCount) { - if (requestInfo != null - && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth - && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + for (int i = 0; i < infoCount; i++) { - return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken, - GetAuthTypeFromRequest(requestInfo->pInfo->AuthType).ToString())); + var info = &requestInfo[i]; + if (requestInfo != null + && info->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && info->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + { + return new WindowsPrincipal(new WindowsIdentity(info->pInfo->AccessToken, + GetAuthTypeFromRequest(info->pInfo->AuthType).ToString())); + } } return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs new file mode 100644 index 0000000000..e7d24271d9 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs @@ -0,0 +1,39 @@ +// Copyright (c) .NET Foundation. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using Microsoft.Win32.SafeHandles; + +namespace Microsoft.Net.Http.Server +{ + internal sealed class HeapAllocHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private static readonly IntPtr ProcessHeap = UnsafeNclNativeMethods.GetProcessHeap(); + + // Called by P/Invoke when returning SafeHandles + private HeapAllocHandle() + : base(ownsHandle: true) + { + } + + // Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you. + protected override bool ReleaseHandle() + { + return UnsafeNclNativeMethods.HeapFree(ProcessHeap, 0, handle); + } + } +} diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs new file mode 100644 index 0000000000..08aaeb2973 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs @@ -0,0 +1,94 @@ +// Copyright (c) .NET Foundation. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Runtime.InteropServices; +using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods.HttpApi; +using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods.TokenBinding; + +namespace Microsoft.Net.Http.Server +{ + /// + /// Contains helpers for dealing with TLS token binding. + /// + internal unsafe static class TokenBindingUtil + { + private static byte[] ExtractIdentifierBlob(TOKENBINDING_RESULT_DATA* pTokenBindingResultData) + { + // Per http://tools.ietf.org/html/draft-ietf-tokbind-protocol-00, Sec. 4, + // the identifer is a tuple which contains (token binding type, hash algorithm + // signature algorithm, key data). We'll strip off the token binding type and + // return the remainder (starting with the hash algorithm) as an opaque blob. + byte[] retVal = new byte[checked(pTokenBindingResultData->identifierSize - 1)]; + Marshal.Copy((IntPtr)(&pTokenBindingResultData->identifierData->hashAlgorithm), retVal, 0, retVal.Length); + return retVal; + } + + /// + /// Returns the 'provided' token binding identifier, optionally also returning the + /// 'referred' token binding identifier. Returns null on failure. + /// + public static byte[] GetProvidedTokenIdFromBindingInfo(HTTP_REQUEST_TOKEN_BINDING_INFO* pTokenBindingInfo, out byte[] referredId) + { + byte[] providedId = null; + referredId = null; + + HeapAllocHandle handle = null; + int status = UnsafeNclNativeMethods.TokenBindingVerifyMessage( + pTokenBindingInfo->TokenBinding, + pTokenBindingInfo->TokenBindingSize, + pTokenBindingInfo->KeyType, + pTokenBindingInfo->TlsUnique, + pTokenBindingInfo->TlsUniqueSize, + out handle); + + // No match found or there was an error? + if (status != 0 || handle == null || handle.IsInvalid) + { + return null; + } + + using (handle) + { + // Find the first 'provided' and 'referred' types. + TOKENBINDING_RESULT_LIST* pResultList = (TOKENBINDING_RESULT_LIST*)handle.DangerousGetHandle(); + for (int i = 0; i < pResultList->resultCount; i++) + { + TOKENBINDING_RESULT_DATA* pThisResultData = &pResultList->resultData[i]; + if (pThisResultData->identifierData->bindingType == TOKENBINDING_TYPE.TOKENBINDING_TYPE_PROVIDED) + { + if (providedId != null) + { + return null; // It is invalid to have more than one 'provided' identifier. + } + providedId = ExtractIdentifierBlob(pThisResultData); + } + else if (pThisResultData->identifierData->bindingType == TOKENBINDING_TYPE.TOKENBINDING_TYPE_REFERRED) + { + if (referredId != null) + { + return null; // It is invalid to have more than one 'referred' identifier. + } + referredId = ExtractIdentifierBlob(pThisResultData); + } + } + } + + return providedId; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index 054375cee9..7e48142209 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; namespace Microsoft.Net.Http.Server { - internal static class UnsafeNclNativeMethods + internal static unsafe class UnsafeNclNativeMethods { private const string HTTPAPI = "httpapi.dll"; @@ -38,12 +38,15 @@ namespace Microsoft.Net.Http.Server private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-1.dll"; private const string api_ms_win_core_handle_LIB = "api-ms-win-core-handle-l1-1-0.dll"; private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll"; + private const string api_ms_win_core_heap_LIB = "api-ms-win-core-heap-L1-2-0.dll"; private const string api_ms_win_core_heap_obsolete_LIB = "api-ms-win-core-heap-obsolete-L1-1-0.dll"; private const string api_ms_win_core_kernel32_legacy_LIB = "api-ms-win-core-kernel32-legacy-l1-1-0.dll"; #else private const string KERNEL32 = "kernel32.dll"; private const string SECUR32 = "secur32.dll"; #endif + private const string TOKENBINDING = "tokenbinding.dll"; + // CONSIDER: Make this an enum, requires changing a lot of types from uint to ErrorCodes. internal static class ErrorCodes { @@ -88,6 +91,34 @@ namespace Microsoft.Net.Http.Server SkipSetEventOnHandle = 2 } + [DllImport(TOKENBINDING, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] + public static extern int TokenBindingVerifyMessage( + [In] byte* tokenBindingMessage, + [In] uint tokenBindingMessageSize, + [In] char* keyType, + [In] byte* tlsUnique, + [In] uint tlsUniqueSize, + [Out] out HeapAllocHandle resultList); + + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366569(v=vs.85).aspx +#if DNXCORE50 + [DllImport(api_ms_win_core_heap_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)] +#else + [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)] +#endif + internal static extern IntPtr GetProcessHeap(); + + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366701(v=vs.85).aspx +#if DNXCORE50 + [DllImport(api_ms_win_core_heap_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)] +#else + [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)] +#endif + internal static extern bool HeapFree( + [In] IntPtr hHeap, + [In] uint dwFlags, + [In] IntPtr lpMem); + internal static class SafeNetHandles { #if DNXCORE50 @@ -248,6 +279,9 @@ namespace Microsoft.Net.Http.Server internal enum HTTP_REQUEST_INFO_TYPE { HttpRequestInfoTypeAuth, + HttpRequestInfoTypeChannelBind, + HttpRequestInfoTypeSslProtocol, + HttpRequestInfoTypeSslTokenBinding } internal enum HTTP_RESPONSE_INFO_TYPE @@ -707,6 +741,18 @@ namespace Microsoft.Net.Http.Server char* Realm; } + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_TOKEN_BINDING_INFO + { + public byte* TokenBinding; + public uint TokenBindingSize; + + public byte* TlsUnique; + public uint TlsUniqueSize; + + public char* KeyType; + } + [StructLayout(LayoutKind.Sequential)] internal struct HTTP_TIMEOUT_LIMIT_INFO { @@ -1206,6 +1252,60 @@ namespace Microsoft.Net.Http.Server } } + // from tokenbinding.h + internal static class TokenBinding + { + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct TOKENBINDING_RESULT_DATA + { + public uint identifierSize; + public TOKENBINDING_IDENTIFIER* identifierData; + public TOKENBINDING_EXTENSION_FORMAT extensionFormat; + public uint extensionSize; + public IntPtr extensionData; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TOKENBINDING_IDENTIFIER + { + // Note: If the layout of these fields changes, be sure to make the + // corresponding change to TokenBindingUtil.ExtractIdentifierBlob. + + public TOKENBINDING_TYPE bindingType; + public TOKENBINDING_HASH_ALGORITHM hashAlgorithm; + public TOKENBINDING_SIGNATURE_ALGORITHM signatureAlgorithm; + } + + internal enum TOKENBINDING_TYPE : byte + { + TOKENBINDING_TYPE_PROVIDED = 0, + TOKENBINDING_TYPE_REFERRED = 1, + } + + internal enum TOKENBINDING_HASH_ALGORITHM : byte + { + TOKENBINDING_HASH_ALGORITHM_SHA256 = 4, + } + + internal enum TOKENBINDING_SIGNATURE_ALGORITHM : byte + { + TOKENBINDING_SIGNATURE_ALGORITHM_RSA = 1, + TOKENBINDING_SIGNATURE_ALGORITHM_ECDSAP256 = 3, + } + + internal enum TOKENBINDING_EXTENSION_FORMAT + { + TOKENBINDING_EXTENSION_FORMAT_UNDEFINED = 0, + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct TOKENBINDING_RESULT_LIST + { + public uint resultCount; + public TOKENBINDING_RESULT_DATA* resultData; + } + } + // DACL related stuff [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated natively")] diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 668cc6dfea..51333996fc 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -60,6 +60,8 @@ namespace Microsoft.Net.Http.Server private string _path; private X509Certificate2 _clientCert; + private byte[] _providedTokenBindingId; + private byte[] _referredTokenBindingId; private HeaderCollection _headers; private BoundaryType _contentBoundaryType; @@ -142,8 +144,10 @@ namespace Microsoft.Net.Http.Server _httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, OriginalBlobAddress); _headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); - UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2* requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; - _user = AuthenticationManager.GetUser(requestV2->pRequestInfo); + var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; + _user = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount); + + GetTlsTokenBindingInfo(); // TODO: Verbose log parameters @@ -470,6 +474,38 @@ namespace Microsoft.Net.Http.Server return _clientCert; } + public byte[] GetProvidedTokenBindingId() + { + return _providedTokenBindingId; + } + + public byte[] GetReferredTokenBindingId() + { + return _referredTokenBindingId; + } + + // Only call from the constructor so we can directly access the native request blob. + // This requires Windows 10 and the following reg key: + // Set Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters to Value: EnableSslTokenBinding = 1 [DWORD] + // Then for IE to work you need to set these: + // Key: HKLM\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_ENABLE_TOKEN_BINDING + // Value: "iexplore.exe"=dword:0x00000001 + // Key: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_ENABLE_TOKEN_BINDING + // Value: "iexplore.exe"=dword:00000001 + private unsafe void GetTlsTokenBindingInfo() + { + var nativeRequest = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)_nativeRequestContext.RequestBlob; + for (int i = 0; i < nativeRequest->RequestInfoCount; i++) + { + var pThisInfo = &nativeRequest->pRequestInfo[i]; + if (pThisInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeSslTokenBinding) + { + var pTokenBindingInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO*)pThisInfo->pInfo; + _providedTokenBindingId = TokenBindingUtil.GetProvidedTokenIdFromBindingInfo(pTokenBindingInfo, out _referredTokenBindingId); + } + } + } + // Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be // disposed. internal void DetachBlob(NativeRequestContext memoryBlob) From 7ed0f2e55f4e0ce642d1d459b64f5217a4a95b5d Mon Sep 17 00:00:00 2001 From: Kirthi Krishnamraju Date: Wed, 20 May 2015 17:20:32 -0700 Subject: [PATCH 212/597] React to aspnet\Configuration #195,#198 --- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index f5c87789c6..1c4e9f6497 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -39,7 +39,7 @@ using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Hosting.Server; -using Microsoft.Framework.ConfigurationModel; +using Microsoft.Framework.Configuration; using Microsoft.Framework.Logging; using Microsoft.Net.Http.Server; From e1ab7a69b48a343d9a4ba196dfce141d0eedf747 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 27 May 2015 16:31:56 -0700 Subject: [PATCH 213/597] Updating to release NuGet.config --- NuGet.Config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index da57d47267..0e74a4912d 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,8 @@  - + + - \ No newline at end of file + From 532698abd3b8b8bc471d24291b930c64af50ed59 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 2 Jun 2015 10:16:15 -0700 Subject: [PATCH 214/597] React to CoreCLR Overlapped changes. --- .../AsyncAcceptContext.cs | 6 +- .../NativeInterop/SafeNativeOverlapped.cs | 21 ++- .../Overlapped/DeferredDisposableLifetime.cs | 85 +++++++++++ .../Overlapped/IDeferredDisposable.cs | 10 ++ .../Overlapped/PreAllocatedOverlapped.cs | 51 +++++++ .../Overlapped/ThreadPoolBoundHandle.cs | 143 ++++++++++++++++++ .../ThreadPoolBoundHandleOverlapped.cs | 38 +++++ .../RequestProcessing/ClientCertLoader.cs | 10 +- .../RequestProcessing/NativeRequestContext.cs | 9 +- .../RequestProcessing/RequestStream.cs | 5 + .../RequestStreamAsyncResult.cs | 10 +- .../RequestProcessing/ResponseStream.cs | 5 + .../ResponseStreamAsyncResult.cs | 22 +-- src/Microsoft.Net.Http.Server/WebListener.cs | 17 ++- .../NativeInterop/SafeNativeOverlapped.cs | 97 ------------ src/Microsoft.Net.WebSockets/project.json | 1 - 16 files changed, 385 insertions(+), 145 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs create mode 100644 src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs delete mode 100644 src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs diff --git a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs index 08edc569ac..a03a65a047 100644 --- a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs @@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Server } } - private WebListener Server + internal WebListener Server { get { @@ -152,9 +152,7 @@ namespace Microsoft.Net.Http.Server private static unsafe void IOWaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { // take the ListenerAsyncResult object from the state - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - AsyncAcceptContext asyncResult = (AsyncAcceptContext)callbackOverlapped.AsyncResult; - + var asyncResult = (AsyncAcceptContext)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs index cf8d1f38e4..e1c2709a3e 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs @@ -30,21 +30,18 @@ namespace Microsoft.Net.Http.Server internal class SafeNativeOverlapped : SafeHandle { internal static readonly SafeNativeOverlapped Zero = new SafeNativeOverlapped(); + private ThreadPoolBoundHandle _boundHandle; internal SafeNativeOverlapped() - : this(IntPtr.Zero) - { - } - - internal unsafe SafeNativeOverlapped(NativeOverlapped* handle) - : this((IntPtr)handle) - { - } - - internal SafeNativeOverlapped(IntPtr handle) : base(IntPtr.Zero, true) { - SetHandle(handle); + } + + internal unsafe SafeNativeOverlapped(ThreadPoolBoundHandle boundHandle, NativeOverlapped* handle) + : base(IntPtr.Zero, true) + { + SetHandle((IntPtr)handle); + _boundHandle = boundHandle; } public override bool IsInvalid @@ -76,7 +73,7 @@ namespace Microsoft.Net.Http.Server { unsafe { - Overlapped.Free((NativeOverlapped*)oldHandle); + _boundHandle.FreeNativeOverlapped((NativeOverlapped*)oldHandle); } } return true; diff --git a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs new file mode 100644 index 0000000000..724741009a --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs @@ -0,0 +1,85 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +namespace System.Threading +{ + internal struct DeferredDisposableLifetime where T : class, IDeferredDisposable + { + private int _count; + public bool AddRef(T obj) + { + while (true) + { + int num = Volatile.Read(ref this._count); + if (num < 0) + { + break; + } + int num2 = checked(num + 1); + if (Interlocked.CompareExchange(ref this._count, num2, num) == num) + { + return true; + } + } + throw new ObjectDisposedException(typeof(T).ToString()); + } + public void Release(T obj) + { + int num2; + int num3; + while (true) + { + int num = Volatile.Read(ref this._count); + if (num > 0) + { + num2 = num - 1; + if (Interlocked.CompareExchange(ref this._count, num2, num) == num) + { + break; + } + } + else + { + num3 = num + 1; + if (Interlocked.CompareExchange(ref this._count, num3, num) == num) + { + goto Block_3; + } + } + } + if (num2 == 0) + { + obj.OnFinalRelease(false); + } + return; + Block_3: + if (num3 == -1) + { + obj.OnFinalRelease(true); + } + } + public void Dispose(T obj) + { + int num2; + while (true) + { + int num = Volatile.Read(ref this._count); + if (num < 0) + { + break; + } + num2 = -1 - num; + if (Interlocked.CompareExchange(ref this._count, num2, num) == num) + { + goto Block_1; + } + } + return; + Block_1: + if (num2 == -1) + { + obj.OnFinalRelease(true); + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs new file mode 100644 index 0000000000..7b6395b588 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs @@ -0,0 +1,10 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +namespace System.Threading +{ + internal interface IDeferredDisposable + { + void OnFinalRelease(bool disposed); + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs new file mode 100644 index 0000000000..c4c7b468af --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs @@ -0,0 +1,51 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +namespace System.Threading +{ + public sealed class PreAllocatedOverlapped : IDisposable, IDeferredDisposable + { + internal readonly ThreadPoolBoundHandleOverlapped _overlapped; + private DeferredDisposableLifetime _lifetime; + [CLSCompliant(false)] + public PreAllocatedOverlapped(IOCompletionCallback callback, object state, object pinData) + { + if (callback == null) + { + throw new ArgumentNullException("callback"); + } + this._overlapped = new ThreadPoolBoundHandleOverlapped(callback, state, pinData, this); + } + internal bool AddRef() + { + return this._lifetime.AddRef(this); + } + internal void Release() + { + this._lifetime.Release(this); + } + public void Dispose() + { + this._lifetime.Dispose(this); + GC.SuppressFinalize(this); + } + ~PreAllocatedOverlapped() + { + if (!Environment.HasShutdownStarted) + { + this.Dispose(); + } + } + unsafe void IDeferredDisposable.OnFinalRelease(bool disposed) + { + if (disposed) + { + Overlapped.Free(this._overlapped._nativeOverlapped); + return; + } + this._overlapped._boundHandle = null; + this._overlapped._completed = false; + *this._overlapped._nativeOverlapped = default(NativeOverlapped); + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs new file mode 100644 index 0000000000..2e3234c206 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs @@ -0,0 +1,143 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +using System.Runtime.InteropServices; +namespace System.Threading +{ + public sealed class ThreadPoolBoundHandle : IDisposable + { + private readonly SafeHandle _handle; + private bool _isDisposed; + public SafeHandle Handle + { + get + { + return this._handle; + } + } + private ThreadPoolBoundHandle(SafeHandle handle) + { + this._handle = handle; + } + public static ThreadPoolBoundHandle BindHandle(SafeHandle handle) + { + if (handle == null) + { + throw new ArgumentNullException("handle"); + } + if (handle.IsClosed || handle.IsInvalid) + { + throw new ArgumentException("Invalid Handle", "handle"); + } + try + { + ThreadPool.BindHandle(handle); + } + catch (Exception expr_38) + { + if (expr_38.HResult == -2147024890) + { + throw new ArgumentException("Invalid Handle", "handle"); + } + if (expr_38.HResult == -2147024809) + { + throw new ArgumentException("Already Bound", "handle"); + } + throw; + } + return new ThreadPoolBoundHandle(handle); + } + [CLSCompliant(false)] + public unsafe NativeOverlapped* AllocateNativeOverlapped(IOCompletionCallback callback, object state, object pinData) + { + if (callback == null) + { + throw new ArgumentNullException("callback"); + } + this.EnsureNotDisposed(); + return new ThreadPoolBoundHandleOverlapped(callback, state, pinData, null) + { + _boundHandle = this + }._nativeOverlapped; + } + [CLSCompliant(false)] + public unsafe NativeOverlapped* AllocateNativeOverlapped(PreAllocatedOverlapped preAllocated) + { + if (preAllocated == null) + { + throw new ArgumentNullException("preAllocated"); + } + this.EnsureNotDisposed(); + preAllocated.AddRef(); + NativeOverlapped* nativeOverlapped; + try + { + ThreadPoolBoundHandleOverlapped expr_21 = preAllocated._overlapped; + if (expr_21._boundHandle != null) + { + throw new ArgumentException("Already Allocated", "preAllocated"); + } + expr_21._boundHandle = this; + nativeOverlapped = expr_21._nativeOverlapped; + } + catch + { + preAllocated.Release(); + throw; + } + return nativeOverlapped; + } + [CLSCompliant(false)] + public unsafe void FreeNativeOverlapped(NativeOverlapped* overlapped) + { + if (overlapped == null) + { + throw new ArgumentNullException("overlapped"); + } + ThreadPoolBoundHandleOverlapped overlappedWrapper = ThreadPoolBoundHandle.GetOverlappedWrapper(overlapped, this); + if (overlappedWrapper._boundHandle != this) + { + throw new ArgumentException("Wrong bound handle", "overlapped"); + } + if (overlappedWrapper._preAllocated != null) + { + overlappedWrapper._preAllocated.Release(); + return; + } + Overlapped.Free(overlapped); + } + [CLSCompliant(false)] + public unsafe static object GetNativeOverlappedState(NativeOverlapped* overlapped) + { + if (overlapped == null) + { + throw new ArgumentNullException("overlapped"); + } + return ThreadPoolBoundHandle.GetOverlappedWrapper(overlapped, null)._userState; + } + private unsafe static ThreadPoolBoundHandleOverlapped GetOverlappedWrapper(NativeOverlapped* overlapped, ThreadPoolBoundHandle expectedBoundHandle) + { + ThreadPoolBoundHandleOverlapped result; + try + { + result = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(overlapped); + } + catch (NullReferenceException ex) + { + throw new ArgumentException("Already freed", "overlapped", ex); + } + return result; + } + public void Dispose() + { + this._isDisposed = true; + } + private void EnsureNotDisposed() + { + if (this._isDisposed) + { + throw new ObjectDisposedException(base.GetType().ToString()); + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs new file mode 100644 index 0000000000..7020223dba --- /dev/null +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs @@ -0,0 +1,38 @@ +#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +using System; +namespace System.Threading +{ + internal sealed class ThreadPoolBoundHandleOverlapped : Overlapped + { + private readonly IOCompletionCallback _userCallback; + internal readonly object _userState; + internal PreAllocatedOverlapped _preAllocated; + internal unsafe NativeOverlapped* _nativeOverlapped; + internal ThreadPoolBoundHandle _boundHandle; + internal bool _completed; + public unsafe ThreadPoolBoundHandleOverlapped(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated) + { + this._userCallback = callback; + this._userState = state; + this._preAllocated = preAllocated; + this._nativeOverlapped = base.Pack(new IOCompletionCallback(ThreadPoolBoundHandleOverlapped.CompletionCallback), pinData); + this._nativeOverlapped->OffsetLow = 0; + this._nativeOverlapped->OffsetHigh = 0; + } + private unsafe static void CompletionCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) + { + ThreadPoolBoundHandleOverlapped expr_0B = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(nativeOverlapped); + if (expr_0B._completed) + { + throw new InvalidOperationException("Native Overlapped reused"); + } + expr_0B._completed = true; + if (expr_0B._boundHandle == null) + { + throw new InvalidOperationException("Already freed"); + } + expr_0B._userCallback.Invoke(errorCode, numBytes, nativeOverlapped); + } + } +} +#endif \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs index 5e9d078df6..e859c97964 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs @@ -138,9 +138,9 @@ namespace Microsoft.Net.Http.Server return; } _backingBuffer = new byte[checked((int)size)]; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, _backingBuffer)); + var boundHandle = RequestContext.Server.BoundHandle; + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer)); _memoryBlob = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); } @@ -315,9 +315,7 @@ namespace Microsoft.Net.Http.Server private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - ClientCertLoader asyncResult = (ClientCertLoader)callbackOverlapped.AsyncResult; - + var asyncResult = (ClientCertLoader)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 61f81ebe8c..30ada89d29 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -161,7 +161,8 @@ namespace Microsoft.Net.Http.Server private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size) { uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size; - if (_nativeOverlapped != null && newSize != RequestBuffer.Length) + // We can't reuse overlapped objects + if (_nativeOverlapped != null) { SafeNativeOverlapped nativeOverlapped = _nativeOverlapped; _nativeOverlapped = null; @@ -170,9 +171,9 @@ namespace Microsoft.Net.Http.Server if (_nativeOverlapped == null) { SetBuffer(checked((int)newSize)); - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = _acceptResult; - _nativeOverlapped = new SafeNativeOverlapped(overlapped.Pack(AsyncAcceptContext.IOCallback, RequestBuffer)); + var boundHandle = _acceptResult.Server.BoundHandle; + _nativeOverlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer)); return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); } return RequestBlob; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index d32cb546be..1ef325a151 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -43,6 +43,11 @@ namespace Microsoft.Net.Http.Server _requestContext = httpContext; } + internal RequestContext RequestContext + { + get { return _requestContext; } + } + public override bool CanSeek { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs index 6976d21725..93ad2980bc 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs @@ -64,9 +64,9 @@ namespace Microsoft.Net.Http.Server : this(requestStream, userState, callback) { _dataAlreadyRead = dataAlreadyRead; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, buffer)); + var boundHandle = requestStream.RequestContext.Server.BoundHandle; + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, buffer)); _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); _cancellationRegistration = cancellationRegistration; } @@ -126,9 +126,7 @@ namespace Microsoft.Net.Http.Server private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - RequestStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as RequestStreamAsyncResult; - + var asyncResult = (RequestStreamAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 2ce897c414..c7df4fdff7 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -47,6 +47,11 @@ namespace Microsoft.Net.Http.Server _requestContext = requestContext; } + internal RequestContext RequestContext + { + get { return _requestContext; } + } + public override bool CanSeek { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 16c2e2128c..95f09b4052 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -65,13 +65,13 @@ namespace Microsoft.Net.Http.Server { _sentHeaders = sentHeaders; _cancellationRegistration = cancellationRegistration; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; + var boundHandle = _responseStream.RequestContext.Server.BoundHandle; if (size == 0) { _dataChunks = null; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, null)); + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); } else { @@ -114,7 +114,8 @@ namespace Microsoft.Net.Http.Server } // This call will pin needed memory - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, objectsToPin)); + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin)); if (chunked) { @@ -136,8 +137,7 @@ namespace Microsoft.Net.Http.Server { _sentHeaders = sentHeaders; _cancellationRegistration = cancellationRegistration; - Overlapped overlapped = new Overlapped(); - overlapped.AsyncResult = this; + var boundHandle = ResponseStream.RequestContext.Server.BoundHandle; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. #if DNXCORE50 @@ -162,7 +162,8 @@ namespace Microsoft.Net.Http.Server if (size == 0 || (!size.HasValue && _fileStream.Length == 0)) { _dataChunks = null; - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, null)); + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); } else { @@ -206,7 +207,8 @@ namespace Microsoft.Net.Http.Server } // This call will pin needed memory - _overlapped = new SafeNativeOverlapped(overlapped.Pack(IOCallback, objectsToPin)); + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin)); if (chunked) { @@ -318,9 +320,7 @@ namespace Microsoft.Net.Http.Server private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { - Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); - ResponseStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as ResponseStreamAsyncResult; - + var asyncResult = (ResponseStreamAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped); IOCompleted(asyncResult, errorCode, numBytes); } diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 727001dc81..018058abe9 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -74,6 +74,7 @@ namespace Microsoft.Net.Http.Server private ILogger _logger; private SafeHandle _requestQueueHandle; + private ThreadPoolBoundHandle _boundHandle; private volatile State _state; // m_State is set only within lock blocks, but often read outside locks. private bool _ignoreWriteExceptions; @@ -141,6 +142,11 @@ namespace Microsoft.Net.Http.Server } } + internal ThreadPoolBoundHandle BoundHandle + { + get { return _boundHandle; } + } + internal ulong UrlGroupId { get { return _urlGroupId; } @@ -523,7 +529,7 @@ namespace Microsoft.Net.Http.Server } _requestQueueHandle = requestQueueHandle; - ThreadPool.BindHandle(_requestQueueHandle); + _boundHandle = ThreadPoolBoundHandle.BindHandle(_requestQueueHandle); } private unsafe void CloseRequestQueueHandle() @@ -532,6 +538,10 @@ namespace Microsoft.Net.Http.Server { _requestQueueHandle.Dispose(); } + if (_boundHandle != null) + { + _boundHandle.Dispose(); + } } /// @@ -667,11 +677,10 @@ namespace Microsoft.Net.Http.Server // Debug.WriteLine("Server: Registering connection for disconnect for connection ID: " + connectionId); // Create a nativeOverlapped callback so we can register for disconnect callback - var overlapped = new Overlapped(); var cts = new CancellationTokenSource(); SafeNativeOverlapped nativeOverlapped = null; - nativeOverlapped = new SafeNativeOverlapped(overlapped.UnsafePack( + nativeOverlapped = new SafeNativeOverlapped(_boundHandle, _boundHandle.AllocateNativeOverlapped( (errorCode, numBytes, overlappedPtr) => { // Debug.WriteLine("Server: http.sys disconnect callback fired for connection ID: " + connectionId); @@ -693,7 +702,7 @@ namespace Microsoft.Net.Http.Server cts.Dispose(); }, - null)); + null, null)); uint statusCode; try diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs deleted file mode 100644 index b5501b0d38..0000000000 --- a/src/Microsoft.Net.WebSockets/NativeInterop/SafeNativeOverlapped.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Microsoft.Net.WebSockets -{ - internal class SafeNativeOverlapped : SafeHandle - { - internal static readonly SafeNativeOverlapped Zero = new SafeNativeOverlapped(); - - internal SafeNativeOverlapped() - : this(IntPtr.Zero) - { - } - - internal unsafe SafeNativeOverlapped(NativeOverlapped* handle) - : this((IntPtr)handle) - { - } - - internal SafeNativeOverlapped(IntPtr handle) - : base(IntPtr.Zero, true) - { - SetHandle(handle); - } - - public override bool IsInvalid - { - get { return handle == IntPtr.Zero; } - } - - public void ReinitializeNativeOverlapped() - { - IntPtr handleSnapshot = handle; - - if (handleSnapshot != IntPtr.Zero) - { - unsafe - { - ((NativeOverlapped*)handleSnapshot)->InternalHigh = IntPtr.Zero; - ((NativeOverlapped*)handleSnapshot)->InternalLow = IntPtr.Zero; - ((NativeOverlapped*)handleSnapshot)->EventHandle = IntPtr.Zero; - } - } - } - - protected override bool ReleaseHandle() - { - IntPtr oldHandle = Interlocked.Exchange(ref handle, IntPtr.Zero); - // Do not call free durring AppDomain shutdown, there may be an outstanding operation. - // Overlapped will take care calling free when the native callback completes. - if (oldHandle != IntPtr.Zero && !HasShutdownStarted) - { - unsafe - { - Overlapped.Free((NativeOverlapped*)oldHandle); - } - } - return true; - } - - internal static bool HasShutdownStarted - { - get - { - return Environment.HasShutdownStarted -#if !DNXCORE50 - || AppDomain.CurrentDomain.IsFinalizingForUnload() -#endif - ; - } - } - } -} diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index d78a9994f2..9c05f0f4b9 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -20,7 +20,6 @@ "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", "System.Text.Encoding.Extensions": "4.0.10-beta-*", "System.Threading": "4.0.10-beta-*", - "System.Threading.Overlapped": "4.0.0-beta-*", "System.Threading.Tasks": "4.0.10-beta-*", "System.Threading.Timer": "4.0.0-beta-*", "System.Threading.ThreadPool": "4.0.10-beta-*" From 3c044fb92ef03aa5b55301bb66127fb2fa29f11c Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 4 Jun 2015 11:36:13 -0700 Subject: [PATCH 215/597] #120 Implement response buffering. --- .../FeatureContext.cs | 14 +- .../MessagePump.cs | 5 +- src/Microsoft.Net.Http.Server/Helpers.cs | 94 +++ .../RequestProcessing/BufferBuilder.cs | 50 ++ .../RequestProcessing/HeaderCollection.cs | 37 +- .../RequestProcessing/RequestContext.cs | 4 +- .../RequestProcessing/Response.cs | 234 +++--- .../RequestProcessing/ResponseStream.cs | 773 +++++++----------- .../ResponseStreamAsyncResult.cs | 302 +++---- src/Microsoft.Net.Http.Server/WebListener.cs | 8 + ...t.Server.WebListener.FunctionalTests.xproj | 3 + .../OpaqueUpgradeTests.cs | 5 +- .../ResponseBodyTests.cs | 49 +- .../WebSocketTests.cs | 1 - .../OpaqueUpgradeTests.cs | 1 - .../ResponseBodyTests.cs | 151 +++- .../ResponseHeaderTests.cs | 12 +- .../ResponseSendFileTests.cs | 28 + .../WebSocketTests.cs | 1 - 19 files changed, 945 insertions(+), 827 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/BufferBuilder.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 18a0c9c9c9..10401145c6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -39,6 +39,7 @@ namespace Microsoft.AspNet.Server.WebListener IHttpSendFileFeature, ITlsConnectionFeature, ITlsTokenBindingFeature, + IHttpBufferingFeature, IHttpRequestLifetimeFeature, IHttpWebSocketFeature, IHttpAuthenticationFeature, @@ -97,6 +98,7 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpConnectionFeature), this); _features.Add(typeof(IHttpResponseFeature), this); _features.Add(typeof(IHttpSendFileFeature), this); + _features.Add(typeof(IHttpBufferingFeature), this); _features.Add(typeof(IHttpRequestLifetimeFeature), this); _features.Add(typeof(IHttpAuthenticationFeature), this); _features.Add(typeof(IRequestIdentifierFeature), this); @@ -328,6 +330,16 @@ namespace Microsoft.AspNet.Server.WebListener return Request.GetReferredTokenBindingId(); } + void IHttpBufferingFeature.DisableRequestBuffering() + { + // There is no request buffering. + } + + void IHttpBufferingFeature.DisableResponseBuffering() + { + Response.ShouldBuffer = false; + } + Stream IHttpResponseFeature.Body { get @@ -356,7 +368,7 @@ namespace Microsoft.AspNet.Server.WebListener bool IHttpResponseFeature.HeadersSent { - get { return Response.HeadersSent; } + get { return Response.HasStarted; } } void IHttpResponseFeature.OnSendingHeaders(Action callback, object state) diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index a43d893307..7bfdaead54 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -167,13 +167,14 @@ namespace Microsoft.AspNet.Server.WebListener catch (Exception ex) { LogHelper.LogException(_logger, "ProcessRequestAsync", ex); - if (requestContext.Response.HeadersSent) + if (requestContext.Response.HasStartedSending) { requestContext.Abort(); } else { // We haven't sent a response yet, try to send a 500 Internal Server Error + requestContext.Response.Reset(); SetFatalResponse(requestContext, 500); } } @@ -195,8 +196,6 @@ namespace Microsoft.AspNet.Server.WebListener private static void SetFatalResponse(RequestContext context, int status) { context.Response.StatusCode = status; - context.Response.ReasonPhrase = string.Empty; - context.Response.Headers.Clear(); context.Response.ContentLength = 0; context.Dispose(); } diff --git a/src/Microsoft.Net.Http.Server/Helpers.cs b/src/Microsoft.Net.Http.Server/Helpers.cs index 0d89af2dde..428edffa1d 100644 --- a/src/Microsoft.Net.Http.Server/Helpers.cs +++ b/src/Microsoft.Net.Http.Server/Helpers.cs @@ -21,13 +21,18 @@ // // ----------------------------------------------------------------------- +using System; using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; namespace Microsoft.Net.Http.Server { internal static class Helpers { + internal static readonly byte[] ChunkTerminator = new byte[] { (byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }; + internal static readonly byte[] CRLF = new byte[] { (byte)'\r', (byte)'\n' }; + internal static Task CompletedTask() { return Task.FromResult(null); @@ -49,5 +54,94 @@ namespace Microsoft.Net.Http.Server { return task.ConfigureAwait(continueOnCapturedContext: false); } + + internal static IAsyncResult ToIAsyncResult(this Task task, AsyncCallback callback, object state) + { + var tcs = new TaskCompletionSource(state); + task.ContinueWith(t => + { + if (t.IsFaulted) + { + tcs.TrySetException(t.Exception.InnerExceptions); + } + else if (t.IsCanceled) + { + tcs.TrySetCanceled(); + } + else + { + tcs.TrySetResult(0); + } + + if (callback != null) + { + callback(tcs.Task); + } + }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); + return tcs.Task; + } + + /// + /// A private utility routine to convert an integer to a chunk header, + /// which is an ASCII hex number followed by a CRLF.The header is returned + /// as a byte array. + /// Generates a right-aligned hex string and returns the start offset. + /// + /// Chunk size to be encoded + /// Out parameter where we store offset into buffer. + /// A byte array with the header in int. + internal static ArraySegment GetChunkHeader(int size) + { + uint mask = 0xf0000000; + byte[] header = new byte[10]; + int i; + int offset = -1; + + // Loop through the size, looking at each nibble. If it's not 0 + // convert it to hex. Save the index of the first non-zero + // byte. + + for (i = 0; i < 8; i++, size <<= 4) + { + // offset == -1 means that we haven't found a non-zero nibble + // yet. If we haven't found one, and the current one is zero, + // don't do anything. + + if (offset == -1) + { + if ((size & mask) == 0) + { + continue; + } + } + + // Either we have a non-zero nibble or we're no longer skipping + // leading zeros. Convert this nibble to ASCII and save it. + + uint temp = (uint)size >> 28; + + if (temp < 10) + { + header[i] = (byte)(temp + '0'); + } + else + { + header[i] = (byte)((temp - 10) + 'A'); + } + + // If we haven't found a non-zero nibble yet, we've found one + // now, so remember that. + + if (offset == -1) + { + offset = i; + } + } + + header[8] = (byte)'\r'; + header[9] = (byte)'\n'; + + return new ArraySegment(header, offset, header.Length - offset); + } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/BufferBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/BufferBuilder.cs new file mode 100644 index 0000000000..5cb08d271d --- /dev/null +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/BufferBuilder.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Net.Http.Server +{ + internal class BufferBuilder + { + private List> _buffers = new List>(); + + internal IEnumerable> Buffers + { + get { return _buffers; } + } + + internal int BufferCount + { + get { return _buffers.Count; } + } + + internal int TotalBytes { get; private set; } + + internal void Add(ArraySegment data) + { + _buffers.Add(data); + TotalBytes += data.Count; + } + + public void CopyAndAdd(ArraySegment data) + { + if (data.Count > 0) + { + var temp = new byte[data.Count]; + Buffer.BlockCopy(data.Array, data.Offset, temp, 0, data.Count); + _buffers.Add(new ArraySegment(temp)); + TotalBytes += data.Count; + } + } + + public void Clear() + { + _buffers.Clear(); + TotalBytes = 0; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs index 4699dbd1e1..87ee134733 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs @@ -21,15 +21,15 @@ namespace Microsoft.Net.Http.Server private IDictionary Store { get; set; } - // Readonly after the response has been sent. - internal bool Sent { get; set; } + // Readonly after the response has been started. + public bool IsReadOnly { get; internal set; } public string this[string key] { get { return Get(key); } set { - ThrowIfSent(); + ThrowIfReadOnly(); if (string.IsNullOrEmpty(value)) { Remove(key); @@ -46,7 +46,7 @@ namespace Microsoft.Net.Http.Server get { return Store[key]; } set { - ThrowIfSent(); + ThrowIfReadOnly(); Store[key] = value; } } @@ -56,11 +56,6 @@ namespace Microsoft.Net.Http.Server get { return Store.Count; } } - public bool IsReadOnly - { - get { return Sent; } - } - public ICollection Keys { get { return Store.Keys; } @@ -73,19 +68,19 @@ namespace Microsoft.Net.Http.Server public void Add(KeyValuePair item) { - ThrowIfSent(); + ThrowIfReadOnly(); Store.Add(item); } public void Add(string key, string[] value) { - ThrowIfSent(); + ThrowIfReadOnly(); Store.Add(key, value); } public void Append(string key, string value) { - ThrowIfSent(); + ThrowIfReadOnly(); string[] values; if (Store.TryGetValue(key, out values)) { @@ -102,7 +97,7 @@ namespace Microsoft.Net.Http.Server public void AppendValues(string key, params string[] values) { - ThrowIfSent(); + ThrowIfReadOnly(); string[] oldValues; if (Store.TryGetValue(key, out oldValues)) { @@ -119,7 +114,7 @@ namespace Microsoft.Net.Http.Server public void Clear() { - ThrowIfSent(); + ThrowIfReadOnly(); Store.Clear(); } @@ -165,25 +160,25 @@ namespace Microsoft.Net.Http.Server public bool Remove(KeyValuePair item) { - ThrowIfSent(); + ThrowIfReadOnly(); return Store.Remove(item); } public bool Remove(string key) { - ThrowIfSent(); + ThrowIfReadOnly(); return Store.Remove(key); } public void Set(string key, string value) { - ThrowIfSent(); + ThrowIfReadOnly(); Store[key] = new[] { value }; } public void SetValues(string key, params string[] values) { - ThrowIfSent(); + ThrowIfReadOnly(); Store[key] = values; } @@ -197,11 +192,11 @@ namespace Microsoft.Net.Http.Server return GetEnumerator(); } - private void ThrowIfSent() + private void ThrowIfReadOnly() { - if (Sent) + if (IsReadOnly) { - throw new InvalidOperationException("The response headers cannot be modified because they have already been sent."); + throw new InvalidOperationException("The response headers cannot be modified because the response has already started."); } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index b2232554ca..757cb4e7de 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -158,9 +158,9 @@ namespace Microsoft.Net.Http.Server public Task UpgradeAsync() { - if (!IsUpgradableRequest || _response.HeadersSent) + if (!IsUpgradableRequest || _response.HasStarted) { - throw new InvalidOperationException(); + throw new InvalidOperationException("This request cannot be upgraded. It is incompatible, or the response has already started."); } // Set the status code and reason phrase diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index d0cf0c98a7..e33a031e5f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -33,6 +33,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Framework.Logging; +using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; namespace Microsoft.Net.Http.Server { @@ -46,18 +47,34 @@ namespace Microsoft.Net.Http.Server private ResponseStream _nativeStream; private long _expectedBodyLength; private BoundaryType _boundaryType; - private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 _nativeResponse; + private HttpApi.HTTP_RESPONSE_V2 _nativeResponse; private IList, object>> _onSendingHeadersActions; private IList, object>> _onResponseCompletedActions; private RequestContext _requestContext; + private bool _bufferingEnabled; - internal Response(RequestContext httpContext) + internal Response(RequestContext requestContext) { // TODO: Verbose log - _requestContext = httpContext; - _nativeResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2(); + _requestContext = requestContext; _headers = new HeaderCollection(); + Reset(); + } + + public void Reset() + { + if (_responseState >= ResponseState.StartedSending) + { + _requestContext.Abort(); + throw new InvalidOperationException("The response has already been sent. Request Aborted."); + } + // We haven't started yet, or we're just buffered, we can clear any data, headers, and state so + // that we can start over (e.g. to write an error message). + _nativeResponse = new HttpApi.HTTP_RESPONSE_V2(); + _headers.IsReadOnly = false; + _headers.Clear(); + _reasonPhrase = null; _boundaryType = BoundaryType.None; _nativeResponse.Response_V1.StatusCode = (ushort)HttpStatusCode.OK; _nativeResponse.Response_V1.Version.MajorVersion = 1; @@ -65,13 +82,17 @@ namespace Microsoft.Net.Http.Server _responseState = ResponseState.Created; _onSendingHeadersActions = new List, object>>(); _onResponseCompletedActions = new List, object>>(); + _bufferingEnabled = _requestContext.Server.BufferResponses; + _expectedBodyLength = 0; + _nativeStream = null; } private enum ResponseState { Created, + Started, ComputedHeaders, - SentHeaders, + StartedSending, Closed, } @@ -105,14 +126,6 @@ namespace Microsoft.Net.Http.Server } } - private void CheckResponseStarted() - { - if (_responseState >= ResponseState.SentHeaders) - { - throw new InvalidOperationException("Headers already sent."); - } - } - public string ReasonPhrase { get { return _reasonPhrase; } @@ -124,6 +137,16 @@ namespace Microsoft.Net.Http.Server } } + public bool ShouldBuffer + { + get { return _bufferingEnabled; } + set + { + CheckResponseStarted(); + _bufferingEnabled = value; + } + } + public Stream Body { get @@ -168,10 +191,7 @@ namespace Microsoft.Net.Http.Server internal long ExpectedBodyLength { - get - { - return _expectedBodyLength; - } + get { return _expectedBodyLength; } } // Header accessors @@ -248,6 +268,7 @@ namespace Microsoft.Net.Http.Server { return; } + Start(); NotifyOnResponseCompleted(); // TODO: Verbose log EnsureResponseStream(); @@ -259,26 +280,30 @@ namespace Microsoft.Net.Http.Server internal BoundaryType BoundaryType { - get - { - return _boundaryType; - } + get { return _boundaryType; } } - public bool HeadersSent + public bool HasStarted { - get + get { return _responseState >= ResponseState.Started; } + } + + private void CheckResponseStarted() + { + if (HasStarted) { - return _responseState >= ResponseState.SentHeaders; + throw new InvalidOperationException("Headers already sent."); } } internal bool ComputedHeaders { - get - { - return _responseState >= ResponseState.ComputedHeaders; - } + get { return _responseState >= ResponseState.ComputedHeaders; } + } + + public bool HasStartedSending + { + get { return _responseState >= ResponseState.StartedSending; } } private void EnsureResponseStream() @@ -319,14 +344,14 @@ namespace Microsoft.Net.Http.Server // What would we loose by bypassing HttpSendHttpResponse? // // TODO: Consider using the HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA flag for most/all responses rather than just Opaque. - internal unsafe uint SendHeaders(UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* pDataChunk, + internal unsafe uint SendHeaders(HttpApi.HTTP_DATA_CHUNK[] dataChunks, ResponseStreamAsyncResult asyncResult, - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags, + HttpApi.HTTP_FLAGS flags, bool isOpaqueUpgrade) { - Debug.Assert(!HeadersSent, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); + Debug.Assert(!HasStartedSending, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); - _responseState = ResponseState.SentHeaders; + _responseState = ResponseState.StartedSending; var reasonPhrase = GetReasonPhrase(StatusCode); if (RequestContext.Logger.IsEnabled(LogLevel.Verbose)) @@ -344,10 +369,16 @@ namespace Microsoft.Net.Http.Server List pinnedHeaders = SerializeHeaders(isOpaqueUpgrade); try { - if (pDataChunk != null) + if (dataChunks != null) { - _nativeResponse.Response_V1.EntityChunkCount = 1; - _nativeResponse.Response_V1.pEntityChunks = pDataChunk; + if (pinnedHeaders == null) + { + pinnedHeaders = new List(); + } + var handle = GCHandle.Alloc(dataChunks, GCHandleType.Pinned); + pinnedHeaders.Add(handle); + _nativeResponse.Response_V1.EntityChunkCount = (ushort)dataChunks.Length; + _nativeResponse.Response_V1.pEntityChunks = (HttpApi.HTTP_DATA_CHUNK*)handle.AddrOfPinnedObject(); } else if (asyncResult != null && asyncResult.DataChunks != null) { @@ -360,45 +391,16 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.pEntityChunks = null; } - if (reasonPhrase.Length > 0) + byte[] reasonPhraseBytes = new byte[HeaderEncoding.GetByteCount(reasonPhrase)]; + fixed (byte* pReasonPhrase = reasonPhraseBytes) { - byte[] reasonPhraseBytes = new byte[HeaderEncoding.GetByteCount(reasonPhrase)]; - fixed (byte* pReasonPhrase = reasonPhraseBytes) - { - _nativeResponse.Response_V1.ReasonLength = (ushort)reasonPhraseBytes.Length; - HeaderEncoding.GetBytes(reasonPhrase, 0, reasonPhraseBytes.Length, reasonPhraseBytes, 0); - _nativeResponse.Response_V1.pReason = (sbyte*)pReasonPhrase; - fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2* pResponse = &_nativeResponse) - { - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( - RequestContext.RequestQueueHandle, - Request.RequestId, - (uint)flags, - pResponse, - null, - &bytesSent, - SafeLocalFree.Zero, - 0, - asyncResult == null ? SafeNativeOverlapped.Zero : asyncResult.NativeOverlapped, - IntPtr.Zero); - - if (asyncResult != null && - statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - WebListener.SkipIOCPCallbackOnSuccess) - { - asyncResult.BytesSent = bytesSent; - // The caller will invoke IOCompleted - } - } - } - } - else - { - fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2* pResponse = &_nativeResponse) + _nativeResponse.Response_V1.ReasonLength = (ushort)reasonPhraseBytes.Length; + HeaderEncoding.GetBytes(reasonPhrase, 0, reasonPhraseBytes.Length, reasonPhraseBytes, 0); + _nativeResponse.Response_V1.pReason = (sbyte*)pReasonPhrase; + fixed (HttpApi.HTTP_RESPONSE_V2* pResponse = &_nativeResponse) { statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( + HttpApi.HttpSendHttpResponse( RequestContext.RequestQueueHandle, Request.RequestId, (uint)flags, @@ -411,7 +413,7 @@ namespace Microsoft.Net.Http.Server IntPtr.Zero); if (asyncResult != null && - statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + statusCode == ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { asyncResult.BytesSent = bytesSent; @@ -427,10 +429,20 @@ namespace Microsoft.Net.Http.Server return statusCode; } - internal UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS ComputeHeaders(bool endOfRequest = false) + internal void Start() { - // Notify that this is absolutely the last chance to make changes. - NotifyOnSendingHeaders(); + if (!HasStarted) + { + // Notify that this is absolutely the last chance to make changes. + NotifyOnSendingHeaders(); + Headers.IsReadOnly = true; // Prohibit further modifications. + _responseState = ResponseState.Started; + } + } + + internal HttpApi.HTTP_FLAGS ComputeHeaders(bool endOfRequest = false, int bufferedBytes = 0) + { + Headers.IsReadOnly = false; // Temporarily allow modification. // 401 if (StatusCode == (ushort)HttpStatusCode.Unauthorized) @@ -438,7 +450,7 @@ namespace Microsoft.Net.Http.Server RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(RequestContext); } - var flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + var flags = HttpApi.HTTP_FLAGS.NONE; Debug.Assert(!ComputedHeaders, "HttpListenerResponse::ComputeHeaders()|ComputedHeaders is true."); _responseState = ResponseState.ComputedHeaders; @@ -478,14 +490,18 @@ namespace Microsoft.Net.Http.Server // The application is performing it's own chunking. _boundaryType = BoundaryType.PassThrough; } - else if (endOfRequest && !(isHeadRequest && statusCanHaveBody)) // HEAD requests always end without a body. Assume a GET response would have a body. + else if (endOfRequest && !(isHeadRequest && statusCanHaveBody)) // HEAD requests should always end without a body. Assume a GET response would have a body. { - if (statusCanHaveBody) + if (bufferedBytes > 0) + { + Headers[HttpKnownHeaderNames.ContentLength] = bufferedBytes.ToString(CultureInfo.InvariantCulture); + } + else if (statusCanHaveBody) { Headers[HttpKnownHeaderNames.ContentLength] = Constants.Zero; } _boundaryType = BoundaryType.ContentLength; - _expectedBodyLength = 0; + _expectedBodyLength = bufferedBytes; } else if (keepConnectionAlive && requestVersion == Constants.V1_1) { @@ -508,9 +524,10 @@ namespace Microsoft.Net.Http.Server { Headers.Append(HttpKnownHeaderNames.Connection, Constants.Close); } - flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; + flags = HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } + Headers.IsReadOnly = true; // Prohibit further modifications. return flags; } @@ -521,9 +538,9 @@ namespace Microsoft.Net.Http.Server private List SerializeHeaders(bool isOpaqueUpgrade) { - Headers.Sent = true; // Prohibit further modifications. - UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; - UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; + Headers.IsReadOnly = true; // Prohibit further modifications. + HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; + HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; List pinnedHeaders; GCHandle gcHandle; /* @@ -552,11 +569,11 @@ namespace Microsoft.Net.Http.Server continue; } // See if this is an unknown header - lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); + lookup = HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. if (lookup == -1 || - (isOpaqueUpgrade && lookup == (int)UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) + (isOpaqueUpgrade && lookup == (int)HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { numUnknownHeaders += headerPair.Value.Length; } @@ -569,7 +586,7 @@ namespace Microsoft.Net.Http.Server try { - fixed (UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER* pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders) + fixed (HttpApi.HTTP_KNOWN_HEADER* pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders) { foreach (KeyValuePair headerPair in Headers) { @@ -580,18 +597,18 @@ namespace Microsoft.Net.Http.Server } headerName = headerPair.Key; string[] headerValues = headerPair.Value; - lookup = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); + lookup = HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. if (lookup == -1 || - (isOpaqueUpgrade && lookup == (int)UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) + (isOpaqueUpgrade && lookup == (int)HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { if (unknownHeaders == null) { - unknownHeaders = new UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[numUnknownHeaders]; + unknownHeaders = new HttpApi.HTTP_UNKNOWN_HEADER[numUnknownHeaders]; gcHandle = GCHandle.Alloc(unknownHeaders, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - _nativeResponse.Response_V1.Headers.pUnknownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + _nativeResponse.Response_V1.Headers.pUnknownHeaders = (HttpApi.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); } for (int headerValueIndex = 0; headerValueIndex < headerValues.Length; headerValueIndex++) @@ -632,29 +649,29 @@ namespace Microsoft.Net.Http.Server { if (knownHeaderInfo == null) { - knownHeaderInfo = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[numKnownMultiHeaders]; + knownHeaderInfo = new HttpApi.HTTP_RESPONSE_INFO[numKnownMultiHeaders]; gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - _nativeResponse.pResponseInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); + _nativeResponse.pResponseInfo = (HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); } - knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = #if DNXCORE50 - (uint)Marshal.SizeOf(); + (uint)Marshal.SizeOf(); #else - (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); + (uint)Marshal.SizeOf(typeof(HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); #endif - UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); + HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); - header.HeaderId = (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.Enum)lookup; - header.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only. + header.HeaderId = (HttpApi.HTTP_RESPONSE_HEADER_ID.Enum)lookup; + header.Flags = HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only. - UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER[headerValues.Length]; + HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApi.HTTP_KNOWN_HEADER[headerValues.Length]; gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - header.KnownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + header.KnownHeaders = (HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); for (int headerValueIndex = 0; headerValueIndex < headerValues.Length; headerValueIndex++) { @@ -672,7 +689,7 @@ namespace Microsoft.Net.Http.Server // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - knownHeaderInfo[_nativeResponse.ResponseInfoCount].pInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); + knownHeaderInfo[_nativeResponse.ResponseInfoCount].pInfo = (HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); _nativeResponse.ResponseInfoCount++; } @@ -704,18 +721,18 @@ namespace Microsoft.Net.Http.Server // Subset of ComputeHeaders internal void SendOpaqueUpgrade() { - // TODO: Should we do this notification earlier when you still have a chance to change the status code to avoid an upgrade? // Notify that this is absolutely the last chance to make changes. - NotifyOnSendingHeaders(); + Start(); + _boundaryType = BoundaryType.Close; // TODO: Send headers async? ulong errorCode = SendHeaders(null, null, - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE | - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA | - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA, + HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE | + HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA | + HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA, true); - if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + if (errorCode != ErrorCodes.ERROR_SUCCESS) { throw new WebListenerException((int)errorCode); } @@ -725,7 +742,7 @@ namespace Microsoft.Net.Http.Server { if (_responseState >= ResponseState.Closed) { - throw new ObjectDisposedException(this.GetType().FullName); + throw new ObjectDisposedException(GetType().FullName); } } @@ -746,6 +763,7 @@ namespace Microsoft.Net.Http.Server internal void SwitchToOpaqueMode() { EnsureResponseStream(); + _bufferingEnabled = false; _nativeStream.SwitchToOpaqueMode(); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index c7df4fdff7..c00c8af45f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -22,23 +22,27 @@ // ------------------------------------------------------------------------------ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; namespace Microsoft.Net.Http.Server { internal class ResponseStream : Stream { - private static readonly byte[] ChunkTerminator = new byte[] { (byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }; + private const int MaxBufferSize = 4 * 1024; private RequestContext _requestContext; private long _leftToWrite = long.MinValue; private bool _closed; private bool _inOpaqueMode; + private BufferBuilder _buffer = new BufferBuilder(); + // The last write needs special handling to cancel. private ResponseStreamAsyncResult _lastWrite; @@ -99,49 +103,185 @@ namespace Microsoft.Net.Http.Server // Send headers public override void Flush() { - if (_closed || _requestContext.Response.HeadersSent) + if (_closed) { return; } - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); - // TODO: Verbose log + FlushInternal(endOfRequest: false); + } + private unsafe void FlushInternal(bool endOfRequest) + { + bool startedSending = _requestContext.Response.HasStartedSending; + var byteCount = _buffer.TotalBytes; + if (byteCount == 0 && startedSending && !endOfRequest) + { + // Empty flush + return; + } + + var flags = ComputeLeftToWrite(endOfRequest); + if (!_inOpaqueMode && endOfRequest && _leftToWrite > byteCount) + { + _requestContext.Abort(); + // This is logged rather than thrown because it is too late for an exception to be visible in user code. + LogHelper.LogError(_requestContext.Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length."); + return; + } + + if (endOfRequest && _requestContext.Response.BoundaryType == BoundaryType.Close) + { + flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; + } + else if (!endOfRequest && _leftToWrite != byteCount) + { + flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + } + + UpdateWritenCount((uint)byteCount); + uint statusCode = 0; + HttpApi.HTTP_DATA_CHUNK[] dataChunks; + var pinnedBuffers = PinDataBuffers(endOfRequest, out dataChunks); try { - uint statusCode; - unsafe + if (!startedSending) { - // TODO: Don't add MoreData flag if content-length == 0? - flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - statusCode = _requestContext.Response.SendHeaders(null, null, flags, false); + statusCode = _requestContext.Response.SendHeaders(dataChunks, null, flags, false); } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + else { - throw new IOException(string.Empty, new WebListenerException((int)statusCode)); + fixed (HttpApi.HTTP_DATA_CHUNK* pDataChunks = dataChunks) + { + statusCode = HttpApi.HttpSendResponseEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + (uint)flags, + (ushort)dataChunks.Length, + pDataChunks, + null, + SafeLocalFree.Zero, + 0, + SafeNativeOverlapped.Zero, + IntPtr.Zero); + } + + if (_requestContext.Server.IgnoreWriteExceptions) + { + statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; + } } } - catch (Exception e) + finally { - LogHelper.LogException(_requestContext.Logger, "Flush", e); + FreeDataBuffers(pinnedBuffers); + _buffer.Clear(); + } + + if (statusCode != ErrorCodes.ERROR_SUCCESS && statusCode != ErrorCodes.ERROR_HANDLE_EOF + // Don't throw for disconnects, we were already finished with the response. + && (!endOfRequest || (statusCode != ErrorCodes.ERROR_CONNECTION_INVALID && statusCode != ErrorCodes.ERROR_INVALID_PARAMETER))) + { + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + LogHelper.LogException(_requestContext.Logger, "Flush", exception); Abort(); - throw; + throw exception; } } - // Send headers - public override Task FlushAsync(CancellationToken cancellationToken) + private List PinDataBuffers(bool endOfRequest, out HttpApi.HTTP_DATA_CHUNK[] dataChunks) { - if (_closed || _requestContext.Response.HeadersSent) + var pins = new List(); + var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; + + var currentChunk = 0; + // Figure out how many data chunks + if (chunked && _buffer.TotalBytes == 0 && endOfRequest) + { + dataChunks = new HttpApi.HTTP_DATA_CHUNK[1]; + SetDataChunk(dataChunks, ref currentChunk, pins, new ArraySegment(Helpers.ChunkTerminator)); + return pins; + } + else if (_buffer.TotalBytes == 0) + { + // No data + dataChunks = new HttpApi.HTTP_DATA_CHUNK[0]; + return pins; + } + + var chunkCount = _buffer.BufferCount; + if (chunked) + { + // Chunk framing + chunkCount += 2; + + if (endOfRequest) + { + // Chunk terminator + chunkCount += 1; + } + } + dataChunks = new HttpApi.HTTP_DATA_CHUNK[chunkCount]; + + if (chunked) + { + var chunkHeaderBuffer = Helpers.GetChunkHeader(_buffer.TotalBytes); + SetDataChunk(dataChunks, ref currentChunk, pins, chunkHeaderBuffer); + } + + foreach (var buffer in _buffer.Buffers) + { + SetDataChunk(dataChunks, ref currentChunk, pins, buffer); + } + + if (chunked) + { + SetDataChunk(dataChunks, ref currentChunk, pins, new ArraySegment(Helpers.CRLF)); + + if (endOfRequest) + { + SetDataChunk(dataChunks, ref currentChunk, pins, new ArraySegment(Helpers.ChunkTerminator)); + } + } + + return pins; + } + + private static void SetDataChunk(HttpApi.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, List pins, ArraySegment buffer) + { + var handle = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); + pins.Add(handle); + chunks[chunkIndex].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + chunks[chunkIndex].fromMemory.pBuffer = handle.AddrOfPinnedObject() + buffer.Offset; + chunks[chunkIndex].fromMemory.BufferLength = (uint)buffer.Count; + chunkIndex++; + } + + private void FreeDataBuffers(List pinnedBuffers) + { + foreach (var pin in pinnedBuffers) + { + if (pin.IsAllocated) + { + pin.Free(); + } + } + } + + + // Simpler than Flush because it will never be called at the end of the request from Dispose. + public unsafe override Task FlushAsync(CancellationToken cancellationToken) + { + if (_closed) { return Helpers.CompletedTask(); } - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); - // TODO: Verbose log - if (cancellationToken.IsCancellationRequested) + bool startedSending = _requestContext.Response.HasStartedSending; + var byteCount = _buffer.TotalBytes; + if (byteCount == 0 && startedSending) { - return Helpers.CanceledTask(); + // Empty flush + return Helpers.CompletedTask(); } var cancellationRegistration = default(CancellationTokenRegistration); @@ -150,26 +290,37 @@ namespace Microsoft.Net.Http.Server cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); } - // TODO: Don't add MoreData flag if content-length == 0? - flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, null, 0, 0, _requestContext.Response.BoundaryType == BoundaryType.Chunked, false, cancellationRegistration); + var flags = ComputeLeftToWrite(); + if (_leftToWrite != byteCount) + { + flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + } + UpdateWritenCount((uint)byteCount); + uint statusCode = 0; + var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; + var asyncResult = new ResponseStreamAsyncResult(this, _buffer, chunked, cancellationRegistration); + uint bytesSent = 0; try { - uint statusCode; - unsafe + if (!startedSending) { statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); + bytesSent = asyncResult.BytesSent; } - - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) + else { - // IO operation completed synchronously - callback won't be called to signal completion. - asyncResult.IOCompleted(statusCode); - } - else if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) - { - throw new IOException(string.Empty, new WebListenerException((int)statusCode)); + statusCode = HttpApi.HttpSendResponseEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + (uint)flags, + asyncResult.DataChunkCount, + asyncResult.DataChunks, + &bytesSent, + SafeLocalFree.Zero, + 0, + asyncResult.NativeOverlapped, + IntPtr.Zero); } } catch (Exception e) @@ -180,6 +331,34 @@ namespace Microsoft.Net.Http.Server throw; } + if (statusCode != ErrorCodes.ERROR_SUCCESS && statusCode != ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (_requestContext.Server.IgnoreWriteExceptions && startedSending) + { + asyncResult.Complete(); + } + else + { + Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + LogHelper.LogException(_requestContext.Logger, "FlushAsync", exception); + Abort(); + throw exception; + } + } + + if (statusCode == ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.IOCompleted(statusCode, bytesSent); + } + + // Last write, cache it for special cancellation handling. + if ((flags & HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) + { + _lastWrite = asyncResult; + } + return asyncResult.Task; } @@ -195,13 +374,13 @@ namespace Microsoft.Net.Http.Server throw new NotSupportedException(Resources.Exception_NoSeek); } - public override int Read([In, Out] byte[] buffer, int offset, int size) + public override int Read([In, Out] byte[] buffer, int offset, int count) { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } #if !DNXCORE50 - public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } @@ -225,7 +404,7 @@ namespace Microsoft.Net.Http.Server UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; if (!_requestContext.Response.ComputedHeaders) { - flags = _requestContext.Response.ComputeHeaders(endOfRequest: endOfRequest); + flags = _requestContext.Response.ComputeHeaders(endOfRequest, _buffer.TotalBytes); } if (_leftToWrite == long.MinValue) { @@ -246,229 +425,56 @@ namespace Microsoft.Net.Http.Server return flags; } - public override unsafe void Write(byte[] buffer, int offset, int size) + public override void Write(byte[] buffer, int offset, int count) { - 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"); - } - if (_closed) - { - throw new ObjectDisposedException(GetType().FullName); - } + // Validates for null and bounds. Allows count == 0. + var data = new ArraySegment(buffer, offset, count); + CheckDisposed(); // TODO: Verbose log parameters - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); - if (size == 0 && _leftToWrite != 0) - { - return; - } - if (_leftToWrite >= 0 && size > _leftToWrite) - { - throw new InvalidOperationException(Resources.Exception_TooMuchWritten); - } - // TODO: Verbose log + // Officially starts the response and fires OnSendingHeaders + _requestContext.Response.Start(); - uint statusCode; - uint dataToWrite = (uint)size; - SafeLocalFree bufferAsIntPtr = null; - IntPtr pBufferAsIntPtr = IntPtr.Zero; - bool sentHeaders = _requestContext.Response.HeadersSent; - try + var currentBytes = _buffer.TotalBytes + data.Count; + var contentLength = _requestContext.Response.ContentLength; + if (contentLength.HasValue && !_requestContext.Response.ComputedHeaders && contentLength.Value <= currentBytes) { - if (size == 0) + if (contentLength.Value < currentBytes) { - // TODO: Is this code path accessible? Is this like a Flush? - statusCode = _requestContext.Response.SendHeaders(null, null, flags, false); - } - else - { - fixed (byte* pDataBuffer = buffer) - { - byte* pBuffer = pDataBuffer; - if (_requestContext.Response.BoundaryType == BoundaryType.Chunked) - { - // TODO: - // here we need some heuristics, some time it is definitely better to split this in 3 write calls - // but for small writes it is probably good enough to just copy the data internally. - 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; i < chunkHeader.Length; i++) - { - Marshal.WriteByte(pBufferAsIntPtr, i, (byte)chunkHeader[i]); - } - Marshal.WriteInt16(pBufferAsIntPtr, chunkHeader.Length, 0x0A0D); - Marshal.Copy(buffer, offset, IntPtrHelper.Add(pBufferAsIntPtr, chunkHeader.Length + 2), size); - Marshal.WriteInt16(pBufferAsIntPtr, (int)(dataToWrite - 2), 0x0A0D); - pBuffer = (byte*)pBufferAsIntPtr; - offset = 0; - } - UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK dataChunk = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - dataChunk.DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - dataChunk.fromMemory.pBuffer = (IntPtr)(pBuffer + offset); - dataChunk.fromMemory.BufferLength = dataToWrite; - - flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - if (!sentHeaders) - { - statusCode = _requestContext.Response.SendHeaders(&dataChunk, null, flags, false); - } - else - { - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, - (uint)flags, - 1, - &dataChunk, - null, - SafeLocalFree.Zero, - 0, - SafeNativeOverlapped.Zero, - IntPtr.Zero); - - if (_requestContext.Server.IgnoreWriteExceptions) - { - statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; - } - } - } + throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); } + // or the last write in a response that hasn't started yet, flush immideately + _buffer.Add(data); + Flush(); } - finally + // The last write in a response that has already started, flush immidately + else if (_requestContext.Response.ComputedHeaders && _leftToWrite >= 0 && _leftToWrite <= currentBytes) { - if (bufferAsIntPtr != null) + if (_leftToWrite < currentBytes) { - // free unmanaged buffer - bufferAsIntPtr.Dispose(); + throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); } + _buffer.Add(data); + Flush(); } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) + else if (_requestContext.Response.ShouldBuffer && currentBytes < MaxBufferSize) { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "Write", exception); - Abort(); - throw exception; + _buffer.CopyAndAdd(data); + } + else + { + // Append to existing data without a copy, and then flush immidately + _buffer.Add(data); + Flush(); } - UpdateWritenCount(dataToWrite); - - // TODO: Verbose log data written } + #if DNXCORE50 - public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) #else - public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) #endif { - 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"); - } - if (_closed) - { - throw new ObjectDisposedException(GetType().FullName); - } - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); - if (size == 0 && _leftToWrite != 0) - { - ResponseStreamAsyncResult result = new ResponseStreamAsyncResult(this, state, callback); - result.Complete(); - return result; - } - if (_leftToWrite >= 0 && size > _leftToWrite) - { - throw new InvalidOperationException(Resources.Exception_TooMuchWritten); - } - // TODO: Verbose log parameters - - uint statusCode; - uint bytesSent = 0; - flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - bool sentHeaders = _requestContext.Response.HeadersSent; - ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, state, callback, buffer, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders); - - // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite. - UpdateWritenCount((uint)((_requestContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size)); - - try - { - if (!sentHeaders) - { - statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); - bytesSent = asyncResult.BytesSent; - } - else - { - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, - (uint)flags, - asyncResult.DataChunkCount, - asyncResult.DataChunks, - &bytesSent, - SafeLocalFree.Zero, - 0, - asyncResult.NativeOverlapped, - IntPtr.Zero); - } - } - catch (Exception e) - { - LogHelper.LogException(_requestContext.Logger, "BeginWrite", e); - asyncResult.Dispose(); - Abort(); - throw; - } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) - { - asyncResult.Dispose(); - if (_requestContext.Server.IgnoreWriteExceptions && sentHeaders) - { - asyncResult.Complete(); - } - else - { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "BeginWrite", exception); - Abort(); - throw exception; - } - } - - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously - callback won't be called to signal completion. - asyncResult.IOCompleted(statusCode, bytesSent); - } - - // Last write, cache it for special cancellation handling. - if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) - { - _lastWrite = asyncResult; - } - - return asyncResult; + return WriteAsync(buffer, offset, count).ToIAsyncResult(callback, state); } #if DNXCORE50 public void EndWrite(IAsyncResult asyncResult) @@ -480,143 +486,58 @@ namespace Microsoft.Net.Http.Server { throw new ArgumentNullException("asyncResult"); } - ResponseStreamAsyncResult castedAsyncResult = asyncResult as ResponseStreamAsyncResult; - if (castedAsyncResult == null || castedAsyncResult.ResponseStream != this) - { - throw new ArgumentException(Resources.Exception_WrongIAsyncResult, "asyncResult"); - } - if (castedAsyncResult.EndCalled) - { - throw new InvalidOperationException(Resources.Exception_EndCalledMultipleTimes); - } - castedAsyncResult.EndCalled = true; - - try - { - // wait & then check for errors - // TODO: Graceful re-throw - castedAsyncResult.Task.Wait(); - } - catch (Exception exception) - { - LogHelper.LogException(_requestContext.Logger, "EndWrite", exception); - Abort(); - throw; - } + ((Task)asyncResult).GetAwaiter().GetResult(); } - public override unsafe Task WriteAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken) + public override unsafe Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - 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"); - } - if (_closed) - { - throw new ObjectDisposedException(GetType().FullName); - } - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); - if (size == 0 && _leftToWrite != 0) - { - return Helpers.CompletedTask(); - } - if (_leftToWrite >= 0 && size > _leftToWrite) - { - throw new InvalidOperationException(Resources.Exception_TooMuchWritten); - } - // TODO: Verbose log - + // Validates for null and bounds. Allows count == 0. + var data = new ArraySegment(buffer, offset, count); if (cancellationToken.IsCancellationRequested) { return Helpers.CanceledTask(); } + CheckDisposed(); + // TODO: Verbose log parameters + // Officially starts the response and fires OnSendingHeaders + _requestContext.Response.Start(); - var cancellationRegistration = default(CancellationTokenRegistration); - if (cancellationToken.CanBeCanceled) + var currentBytes = _buffer.TotalBytes + data.Count; + var contentLength = _requestContext.Response.ContentLength; + if (contentLength.HasValue && !_requestContext.Response.ComputedHeaders && contentLength.Value <= currentBytes) { - cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); - } - - uint statusCode; - uint bytesSent = 0; - flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - bool sentHeaders = _requestContext.Response.HeadersSent; - ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, buffer, offset, size, _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, cancellationRegistration); - - // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite. - UpdateWritenCount((uint)((_requestContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size)); - - try - { - if (!sentHeaders) + if (contentLength.Value < currentBytes) { - statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); - bytesSent = asyncResult.BytesSent; + throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); } - else + // The last write in a response that hasn't started yet, flush immideately + _buffer.Add(data); + return FlushAsync(cancellationToken); + } + // The last write in a response that has already started, flush immidately + else if (_requestContext.Response.ComputedHeaders && _leftToWrite > 0 && _leftToWrite <= currentBytes) + { + if (_leftToWrite < currentBytes) { - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, - (uint)flags, - asyncResult.DataChunkCount, - asyncResult.DataChunks, - &bytesSent, - SafeLocalFree.Zero, - 0, - asyncResult.NativeOverlapped, - IntPtr.Zero); + throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); } + _buffer.Add(data); + return FlushAsync(cancellationToken); } - catch (Exception e) + else if (_requestContext.Response.ShouldBuffer && currentBytes < MaxBufferSize) { - LogHelper.LogException(_requestContext.Logger, "WriteAsync", e); - asyncResult.Dispose(); - Abort(); - throw; + _buffer.CopyAndAdd(data); + return Helpers.CompletedTask(); } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + else { - asyncResult.Dispose(); - if (_requestContext.Server.IgnoreWriteExceptions && sentHeaders) - { - asyncResult.Complete(); - } - else - { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "WriteAsync", exception); - Abort(); - throw exception; - } + // Append to existing data without a copy, and then flush immidately + _buffer.Add(data); + return FlushAsync(cancellationToken); } - - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously - callback won't be called to signal completion. - asyncResult.IOCompleted(statusCode, bytesSent); - } - - // Last write, cache it for special cancellation handling. - if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) - { - _lastWrite = asyncResult; - } - - return asyncResult.Task; } - internal unsafe Task SendFileAsync(string fileName, long offset, long? size, CancellationToken cancellationToken) + internal async Task SendFileAsync(string fileName, long offset, long? count, CancellationToken cancellationToken) { // It's too expensive to validate the file attributes before opening the file. Open the file and then check the lengths. // This all happens inside of ResponseStreamAsyncResult. @@ -624,17 +545,26 @@ namespace Microsoft.Net.Http.Server { throw new ArgumentNullException("fileName"); } - if (_closed) + CheckDisposed(); + if (_buffer.TotalBytes > 0) { - throw new ObjectDisposedException(GetType().FullName); + // SendFileAsync is primarly used for full responses so we don't optimize this partialy buffered scenario. + // In theory we could merge SendFileAsyncCore into FlushAsync[Internal] and send the buffered data in the same call as the file. + await FlushAsync(cancellationToken); } + // We can't mix await and unsafe so seperate the unsafe code into another method. + await SendFileAsyncCore(fileName, offset, count, cancellationToken); + } + internal unsafe Task SendFileAsyncCore(string fileName, long offset, long? count, CancellationToken cancellationToken) + { + _requestContext.Response.Start(); UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); - if (size == 0 && _leftToWrite != 0) + if (count == 0 && _leftToWrite != 0) { return Helpers.CompletedTask(); } - if (_leftToWrite >= 0 && size > _leftToWrite) + if (_leftToWrite >= 0 && count > _leftToWrite) { throw new InvalidOperationException(Resources.Exception_TooMuchWritten); } @@ -653,30 +583,30 @@ namespace Microsoft.Net.Http.Server uint statusCode; uint bytesSent = 0; - flags |= _leftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - bool sentHeaders = _requestContext.Response.HeadersSent; - ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, fileName, offset, size, - _requestContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, cancellationRegistration); + flags |= _leftToWrite == count ? HttpApi.HTTP_FLAGS.NONE : HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + bool startedSending = _requestContext.Response.HasStartedSending; + var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; + ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, fileName, offset, count, chunked, cancellationRegistration); long bytesWritten; - if (_requestContext.Response.BoundaryType == BoundaryType.Chunked) + if (chunked) { bytesWritten = 0; } - else if (size.HasValue) + else if (count.HasValue) { - bytesWritten = size.Value; + bytesWritten = count.Value; } else { bytesWritten = asyncResult.FileLength - offset; } - // Update m_LeftToWrite now so we can queue up additional calls to SendFileAsync. + // Update _leftToWrite now so we can queue up additional calls to SendFileAsync. UpdateWritenCount((uint)bytesWritten); try { - if (!sentHeaders) + if (!startedSending) { statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); bytesSent = asyncResult.BytesSent; @@ -684,8 +614,7 @@ namespace Microsoft.Net.Http.Server else { // TODO: If opaque then include the buffer data flag. - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( + statusCode = HttpApi.HttpSendResponseEntityBody( _requestContext.RequestQueueHandle, _requestContext.RequestId, (uint)flags, @@ -709,7 +638,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) { asyncResult.Dispose(); - if (_requestContext.Server.IgnoreWriteExceptions && sentHeaders) + if (_requestContext.Server.IgnoreWriteExceptions && startedSending) { asyncResult.Complete(); } @@ -722,14 +651,14 @@ namespace Microsoft.Net.Http.Server } } - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode, bytesSent); } // Last write, cache it for special cancellation handling. - if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) + if ((flags & HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) { _lastWrite = asyncResult; } @@ -765,85 +694,7 @@ namespace Microsoft.Net.Http.Server return; } _closed = true; - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(endOfRequest: true); - if (_leftToWrite > 0 && !_inOpaqueMode) - { - _requestContext.Abort(); - // This is logged rather than thrown because it is too late for an exception to be visible in user code. - LogHelper.LogError(_requestContext.Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length."); - return; - } - bool sentHeaders = _requestContext.Response.HeadersSent; - if (sentHeaders && _leftToWrite == 0) - { - return; - } - - uint statusCode = 0; - if ((_requestContext.Response.BoundaryType == BoundaryType.Chunked - || _requestContext.Response.BoundaryType == BoundaryType.Close - || _requestContext.Response.BoundaryType == BoundaryType.PassThrough) - && !_requestContext.Request.IsHeadMethod) - { - if (_requestContext.Response.BoundaryType == BoundaryType.Close) - { - flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; - } - fixed (void* pBuffer = ChunkTerminator) - { - UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* pDataChunk = null; - if (_requestContext.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.fromMemory.pBuffer = (IntPtr)pBuffer; - dataChunk.fromMemory.BufferLength = (uint)ChunkTerminator.Length; - pDataChunk = &dataChunk; - } - if (!sentHeaders) - { - statusCode = _requestContext.Response.SendHeaders(pDataChunk, null, flags, false); - } - else - { - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, - (uint)flags, - pDataChunk != null ? (ushort)1 : (ushort)0, - pDataChunk, - null, - SafeLocalFree.Zero, - 0, - SafeNativeOverlapped.Zero, - IntPtr.Zero); - - if (_requestContext.Server.IgnoreWriteExceptions) - { - statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; - } - } - } - } - else - { - if (!sentHeaders) - { - statusCode = _requestContext.Response.SendHeaders(null, null, flags, false); - } - } - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF - // Don't throw for disconnects, we were already finished with the response. - && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID - && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER) - { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "Dispose", exception); - _requestContext.Abort(); - throw exception; - } - _leftToWrite = 0; + FlushInternal(endOfRequest: true); } } finally @@ -870,5 +721,13 @@ namespace Microsoft.Net.Http.Server UnsafeNclNativeMethods.CancelIoEx(requestQueueHandle, asyncState.NativeOverlapped); } } + + private void CheckDisposed() + { + if (_closed) + { + throw new ObjectDisposedException(GetType().FullName); + } + } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 95f09b4052..3510080030 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -27,117 +27,97 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; namespace Microsoft.Net.Http.Server { internal unsafe class ResponseStreamAsyncResult : IAsyncResult, IDisposable { - private static readonly byte[] CRLF = new byte[] { (byte)'\r', (byte)'\n' }; private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(Callback); private SafeNativeOverlapped _overlapped; - private UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[] _dataChunks; - private bool _sentHeaders; + private HttpApi.HTTP_DATA_CHUNK[] _dataChunks; private FileStream _fileStream; private ResponseStream _responseStream; private TaskCompletionSource _tcs; - private AsyncCallback _callback; private uint _bytesSent; private CancellationTokenRegistration _cancellationRegistration; - internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback) + internal ResponseStreamAsyncResult(ResponseStream responseStream, CancellationTokenRegistration cancellationRegistration) { _responseStream = responseStream; - _tcs = new TaskCompletionSource(userState); - _callback = callback; - } - internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback, - byte[] buffer, int offset, int size, bool chunked, bool sentHeaders) - : this(responseStream, userState, callback, buffer, offset, size, chunked, sentHeaders, - new CancellationTokenRegistration()) - { - } - - internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback, - byte[] buffer, int offset, int size, bool chunked, bool sentHeaders, - CancellationTokenRegistration cancellationRegistration) - : this(responseStream, userState, callback) - { - _sentHeaders = sentHeaders; + _tcs = new TaskCompletionSource(); _cancellationRegistration = cancellationRegistration; - var boundHandle = _responseStream.RequestContext.Server.BoundHandle; + } - if (size == 0) + internal ResponseStreamAsyncResult(ResponseStream responseStream, BufferBuilder buffer, bool chunked, + CancellationTokenRegistration cancellationRegistration) + : this(responseStream, cancellationRegistration) + { + var boundHandle = _responseStream.RequestContext.Server.BoundHandle; + object[] objectsToPin; + + if (buffer.TotalBytes == 0) { _dataChunks = null; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, null)); + return; } - else + + _dataChunks = new HttpApi.HTTP_DATA_CHUNK[buffer.BufferCount + (chunked ? 2 : 0)]; + objectsToPin = new object[_dataChunks.Length + 1]; + objectsToPin[0] = _dataChunks; + var currentChunk = 0; + var currentPin = 1; + + var chunkHeaderBuffer = new ArraySegment(); + if (chunked) { - _dataChunks = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1]; - - object[] objectsToPin = new object[1 + _dataChunks.Length]; - objectsToPin[_dataChunks.Length] = _dataChunks; - - int chunkHeaderOffset = 0; - byte[] chunkHeaderBuffer = null; - if (chunked) - { - chunkHeaderBuffer = GetChunkHeader(size, out chunkHeaderOffset); - - _dataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - _dataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - _dataChunks[0].fromMemory.BufferLength = (uint)(chunkHeaderBuffer.Length - chunkHeaderOffset); - - objectsToPin[0] = chunkHeaderBuffer; - - _dataChunks[1] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - _dataChunks[1].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - _dataChunks[1].fromMemory.BufferLength = (uint)size; - - objectsToPin[1] = buffer; - - _dataChunks[2] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - _dataChunks[2].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - _dataChunks[2].fromMemory.BufferLength = (uint)CRLF.Length; - - objectsToPin[2] = CRLF; - } - else - { - _dataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - _dataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - _dataChunks[0].fromMemory.BufferLength = (uint)size; - - objectsToPin[0] = buffer; - } - - // This call will pin needed memory - _overlapped = new SafeNativeOverlapped(boundHandle, - boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin)); - - if (chunked) - { - _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer, chunkHeaderOffset); - _dataChunks[1].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset); - _dataChunks[2].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(CRLF, 0); - } - else - { - _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset); - } + chunkHeaderBuffer = Helpers.GetChunkHeader(buffer.TotalBytes); + SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, chunkHeaderBuffer); } + + foreach (var segment in buffer.Buffers) + { + SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, segment); + } + + if (chunked) + { + SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, new ArraySegment(Helpers.CRLF)); + } + + // This call will pin needed memory + _overlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin)); + + currentChunk = 0; + if (chunked) + { + _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer.Array, chunkHeaderBuffer.Offset); + currentChunk++; + } + foreach (var segment in buffer.Buffers) + { + _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(segment.Array, segment.Offset); + currentChunk++; + } + if (chunked) + { + _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(Helpers.CRLF, 0); + currentChunk++; + } + + // We've captured a reference to all the buffers, clear the buffer so that it can be used to queue overlapped writes. + buffer.Clear(); } - internal ResponseStreamAsyncResult(ResponseStream responseStream, object userState, AsyncCallback callback, - string fileName, long offset, long? size, bool chunked, bool sentHeaders, - CancellationTokenRegistration cancellationRegistration) - : this(responseStream, userState, callback) + internal ResponseStreamAsyncResult(ResponseStream responseStream, string fileName, long offset, + long? count, bool chunked, CancellationTokenRegistration cancellationRegistration) + : this(responseStream, cancellationRegistration) { - _sentHeaders = sentHeaders; - _cancellationRegistration = cancellationRegistration; - var boundHandle = ResponseStream.RequestContext.Server.BoundHandle; + var boundHandle = responseStream.RequestContext.Server.BoundHandle; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. #if DNXCORE50 @@ -153,13 +133,13 @@ namespace Microsoft.Net.Http.Server _fileStream.Dispose(); throw new ArgumentOutOfRangeException("offset", offset, string.Empty); } - if (size.HasValue && (size < 0 || size > length - offset)) + if (count.HasValue && (count < 0 || count > length - offset)) { _fileStream.Dispose(); - throw new ArgumentOutOfRangeException("size", size, string.Empty); + throw new ArgumentOutOfRangeException("count", count, string.Empty); } - if (size == 0 || (!size.HasValue && _fileStream.Length == 0)) + if (count == 0 || (!count.HasValue && _fileStream.Length == 0)) { _dataChunks = null; _overlapped = new SafeNativeOverlapped(boundHandle, @@ -167,42 +147,34 @@ namespace Microsoft.Net.Http.Server } else { - _dataChunks = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1]; + _dataChunks = new HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1]; object[] objectsToPin = new object[_dataChunks.Length]; objectsToPin[_dataChunks.Length - 1] = _dataChunks; - int chunkHeaderOffset = 0; - byte[] chunkHeaderBuffer = null; + var chunkHeaderBuffer = new ArraySegment(); if (chunked) { - chunkHeaderBuffer = GetChunkHeader((int)(size ?? _fileStream.Length - offset), out chunkHeaderOffset); + chunkHeaderBuffer = Helpers.GetChunkHeader((int)(count ?? _fileStream.Length - offset)); + _dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[0].fromMemory.BufferLength = (uint)chunkHeaderBuffer.Count; + objectsToPin[0] = chunkHeaderBuffer.Array; - _dataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - _dataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - _dataChunks[0].fromMemory.BufferLength = (uint)(chunkHeaderBuffer.Length - chunkHeaderOffset); - - objectsToPin[0] = chunkHeaderBuffer; - - _dataChunks[1] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - _dataChunks[1].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; + _dataChunks[1].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[1].fromFile.offset = (ulong)offset; - _dataChunks[1].fromFile.count = (ulong)(size ?? -1); + _dataChunks[1].fromFile.count = (ulong)(count ?? -1); _dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); // Nothing to pin for the file handle. - _dataChunks[2] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - _dataChunks[2].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - _dataChunks[2].fromMemory.BufferLength = (uint)CRLF.Length; - - objectsToPin[1] = CRLF; + _dataChunks[2].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[2].fromMemory.BufferLength = (uint)Helpers.CRLF.Length; + objectsToPin[1] = Helpers.CRLF; } else { - _dataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - _dataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; + _dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[0].fromFile.offset = (ulong)offset; - _dataChunks[0].fromFile.count = (ulong)(size ?? -1); + _dataChunks[0].fromFile.count = (ulong)(count ?? -1); _dataChunks[0].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); } @@ -212,15 +184,21 @@ namespace Microsoft.Net.Http.Server if (chunked) { - _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer, chunkHeaderOffset); - _dataChunks[2].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(CRLF, 0); + // These must be set after pinning with Overlapped. + _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer.Array, chunkHeaderBuffer.Offset); + _dataChunks[2].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(Helpers.CRLF, 0); } } } - internal ResponseStream ResponseStream + private static void SetDataChunk(HttpApi.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, object[] objectsToPin, ref int pinIndex, ArraySegment segment) { - get { return _responseStream; } + objectsToPin[pinIndex] = segment.Array; + pinIndex++; + chunks[chunkIndex].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + // The address is not set until after we pin it with Overlapped + chunks[chunkIndex].fromMemory.BufferLength = (uint)segment.Count; + chunkIndex++; } internal SafeNativeOverlapped NativeOverlapped @@ -254,7 +232,7 @@ namespace Microsoft.Net.Http.Server } } - internal UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* DataChunks + internal HttpApi.HTTP_DATA_CHUNK* DataChunks { get { @@ -264,7 +242,7 @@ namespace Microsoft.Net.Http.Server } else { - return (UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK*)(Marshal.UnsafeAddrOfPinnedArrayElement(_dataChunks, 0)); + return (HttpApi.HTTP_DATA_CHUNK*)(Marshal.UnsafeAddrOfPinnedArrayElement(_dataChunks, 0)); } } } @@ -326,111 +304,17 @@ namespace Microsoft.Net.Http.Server internal void Complete() { - if (_tcs.TrySetResult(null) && _callback != null) - { - try - { - _callback(this); - } - catch (Exception) - { - // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. - // TODO: Log - } - } + _tcs.TrySetResult(null); Dispose(); } internal void Fail(Exception ex) { - if (_tcs.TrySetException(ex) && _callback != null) - { - try - { - _callback(this); - } - catch (Exception) - { - // TODO: Exception handling? This may be an IO callback thread and throwing here could crash the app. - } - } + _tcs.TrySetException(ex); Dispose(); _responseStream.Abort(); } - /*++ - - GetChunkHeader - - A private utility routine to convert an integer to a chunk header, - which is an ASCII hex number followed by a CRLF. The header is returned - as a byte array. - - Input: - - size - Chunk size to be encoded - offset - Out parameter where we store offset into buffer. - - Returns: - - A byte array with the header in int. - - --*/ - - private static byte[] GetChunkHeader(int size, out int offset) - { - uint mask = 0xf0000000; - byte[] header = new byte[10]; - int i; - offset = -1; - - // Loop through the size, looking at each nibble. If it's not 0 - // convert it to hex. Save the index of the first non-zero - // byte. - - for (i = 0; i < 8; i++, size <<= 4) - { - // offset == -1 means that we haven't found a non-zero nibble - // yet. If we haven't found one, and the current one is zero, - // don't do anything. - - if (offset == -1) - { - if ((size & mask) == 0) - { - continue; - } - } - - // Either we have a non-zero nibble or we're no longer skipping - // leading zeros. Convert this nibble to ASCII and save it. - - uint temp = (uint)size >> 28; - - if (temp < 10) - { - header[i] = (byte)(temp + '0'); - } - else - { - header[i] = (byte)((temp - 10) + 'A'); - } - - // If we haven't found a non-zero nibble yet, we've found one - // now, so remember that. - - if (offset == -1) - { - offset = i; - } - } - - header[8] = (byte)'\r'; - header[9] = (byte)'\n'; - - return header; - } - public object AsyncState { get { return _tcs.Task.AsyncState; } diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 018058abe9..fa8099e275 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -91,6 +91,8 @@ namespace Microsoft.Net.Http.Server // The native request queue private long? _requestQueueLength; + private bool _bufferResponses = true; + public WebListener() : this(null) { @@ -134,6 +136,12 @@ namespace Microsoft.Net.Http.Server get { return _urlPrefixes; } } + public bool BufferResponses + { + get { return _bufferResponses; } + set { _bufferResponses = value; } + } + internal SafeHandle RequestQueueHandle { get diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj index 80131fc053..a7ac76a466 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj @@ -13,5 +13,8 @@ 2.0 + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index fccf18ba9a..6d5057bba3 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -71,6 +71,7 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); await httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.Body.FlushAsync(); try { var opaqueFeature = httpContext.GetFeature(); @@ -171,8 +172,8 @@ namespace Microsoft.AspNet.Server.WebListener using (Stream stream = await SendOpaqueRequestAsync(method, address, extraHeader)) { byte[] data = new byte[100]; - stream.WriteAsync(data, 0, 49).Wait(); - int read = stream.ReadAsync(data, 0, data.Length).Result; + await stream.WriteAsync(data, 0, 49); + int read = await stream.ReadAsync(data, 0, data.Length); Assert.Equal(49, read); } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 7f77ff1880..6c0ae01f85 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; @@ -31,7 +32,7 @@ namespace Microsoft.AspNet.Server.WebListener public class ResponseBodyTests { [Fact] - public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() + public async Task ResponseBody_WriteNoHeaders_BuffersAndSetsContentLength() { string address; using (Utilities.CreateHttpServer(out address, env => @@ -45,24 +46,22 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; - Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); - Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); } } [Fact] - public async Task ResponseBody_WriteChunked_Chunked() + public async Task ResponseBody_WriteNoHeadersAndFlush_DefaultsToChunked() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - httpContext.Request.Headers["transfeR-Encoding"] = " CHunked "; - Stream stream = httpContext.Response.Body; - stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); - stream.Write(new byte[10], 0, 10); - return stream.WriteAsync(new byte[10], 0, 10); + httpContext.Response.Body.Write(new byte[10], 0, 10); + await httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + await httpContext.Response.Body.FlushAsync(); })) { HttpResponseMessage response = await SendRequestAsync(address); @@ -71,7 +70,30 @@ namespace Microsoft.AspNet.Server.WebListener IEnumerable ignored; Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); - Assert.Equal(new byte[30], await response.Content.ReadAsByteArrayAsync()); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_WriteChunked_ManuallyChunked() + { + string address; + using (Utilities.CreateHttpServer(out address, async env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.Headers["transfeR-Encoding"] = " CHunked "; + Stream stream = httpContext.Response.Body; + var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); + await stream.WriteAsync(responseBytes, 0, responseBytes.Length); + })) + { + HttpResponseMessage response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal("Manually Chunked", await response.Content.ReadAsStringAsync()); } } @@ -132,7 +154,7 @@ namespace Microsoft.AspNet.Server.WebListener } [Fact] - public void ResponseBody_WriteContentLengthTooMuchWritten_Throws() + public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { string address; using (Utilities.CreateHttpServer(out address, env => @@ -144,7 +166,8 @@ namespace Microsoft.AspNet.Server.WebListener return Task.FromResult(0); })) { - Assert.Throws(() => SendRequestAsync(address).Result); + var response = await SendRequestAsync(address); + Assert.Equal(500, (int)response.StatusCode); } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index 544ef17a22..6fbcc31eb4 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -84,7 +84,6 @@ namespace Microsoft.AspNet.Server.WebListener { HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); - Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); Assert.True(upgradeThrew.Value); } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index 9d3d0553ec..e077352d42 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -31,7 +31,6 @@ namespace Microsoft.Net.Http.Server context.Dispose(); HttpResponseMessage response = await clientTask; Assert.Equal(200, (int)response.StatusCode); - Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 779b7080fb..8cae679baa 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.Net.Http.Server public class ResponseBodyTests { [Fact] - public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() + public async Task ResponseBody_BufferWriteNoHeaders_DefaultsToContentLength() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -23,6 +23,31 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); + context.Response.ShouldBuffer = true; + context.Response.Body.Write(new byte[10], 0, 10); + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_NoBufferWriteNoHeaders_DefaultsToChunked() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.ShouldBuffer = false; context.Response.Body.Write(new byte[10], 0, 10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); @@ -37,6 +62,29 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task ResponseBody_FlushThenBuffer_DefaultsToChunkedAndTerminates() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Body.Write(new byte[10], 0, 10); + context.Response.Body.Flush(); + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.HasValue); + Assert.Equal(20, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + [Fact] public async Task ResponseBody_WriteChunked_ManuallyChunked() { @@ -111,7 +159,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Throws() + public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Aborts() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -123,6 +171,12 @@ namespace Microsoft.Net.Http.Server context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); + // HttpClient retries the request because it didn't get a response. + context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = " 20 "; + context.Response.Body.Write(new byte[5], 0, 5); + context.Dispose(); + await Assert.ThrowsAsync(() => responseTask); } } @@ -141,6 +195,13 @@ namespace Microsoft.Net.Http.Server Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); + // HttpClient retries the request because it didn't get a response. + context = await server.GetContextAsync(); + context.Response.Headers["Content-lenGth"] = " 10 "; + context.Response.Body.Write(new byte[5], 0, 5); + Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); + context.Dispose(); + await Assert.ThrowsAsync(() => responseTask); } } @@ -170,6 +231,92 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task ResponseBody_WriteZeroCount_StartsResponse() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Body.Write(new byte[10], 0, 0); + Assert.True(context.Response.HasStarted); + await context.Response.Body.WriteAsync(new byte[10], 0, 0); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_WriteMoreThanBufferLimitBufferWithNoHeaders_DefaultsToChunkedAndFlushes() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.ShouldBuffer = true; + for (int i = 0; i < 4; i++) + { + context.Response.Body.Write(new byte[1020], 0, 1020); + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.HasStartedSending); + } + context.Response.Body.Write(new byte[1020], 0, 1020); + Assert.True(context.Response.HasStartedSending); + context.Response.Body.Write(new byte[1020], 0, 1020); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(new byte[1020*6], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task ResponseBody_WriteAsyncMoreThanBufferLimitBufferWithNoHeaders_DefaultsToChunkedAndFlushes() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.ShouldBuffer = true; + for (int i = 0; i < 4; i++) + { + await context.Response.Body.WriteAsync(new byte[1020], 0, 1020); + Assert.True(context.Response.HasStarted); + Assert.False(context.Response.HasStartedSending); + } + await context.Response.Body.WriteAsync(new byte[1020], 0, 1020); + Assert.True(context.Response.HasStartedSending); + await context.Response.Body.WriteAsync(new byte[1020], 0, 1020); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(new byte[1020 * 6], await response.Content.ReadAsByteArrayAsync()); + } + } + [Fact] public async Task ResponseBody_WriteAsyncWithActiveCancellationToken_Success() { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index f16bc98142..2f6648aaf3 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -349,13 +349,13 @@ namespace Microsoft.Net.Http.Server responseHeaders.SetValues("Custom1", "value1a", "value1b"); responseHeaders.SetValues("Custom2", "value2a, value2b"); var body = context.Response.Body; - Assert.False(context.Response.HeadersSent); + Assert.False(context.Response.HasStarted); body.Flush(); - Assert.True(context.Response.HeadersSent); + Assert.True(context.Response.HasStarted); var ex = Assert.Throws(() => context.Response.StatusCode = 404); Assert.Equal("Headers already sent.", ex.Message); ex = Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); - Assert.Equal("The response headers cannot be modified because they have already been sent.", ex.Message); + Assert.Equal("The response headers cannot be modified because the response has already started.", ex.Message); context.Dispose(); @@ -385,13 +385,13 @@ namespace Microsoft.Net.Http.Server responseHeaders.SetValues("Custom1", "value1a", "value1b"); responseHeaders.SetValues("Custom2", "value2a, value2b"); var body = context.Response.Body; - Assert.False(context.Response.HeadersSent); + Assert.False(context.Response.HasStarted); await body.FlushAsync(); - Assert.True(context.Response.HeadersSent); + Assert.True(context.Response.HasStarted); var ex = Assert.Throws(() => context.Response.StatusCode = 404); Assert.Equal("Headers already sent.", ex.Message); ex = Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); - Assert.Equal("The response headers cannot be modified because they have already been sent.", ex.Message); + Assert.Equal("The response headers cannot be modified because the response has already started.", ex.Message); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index b81fd6d514..66014c92db 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -202,6 +202,34 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task ResponseSendFile_EmptyFileCountUnspecified_SetsChunkedAndFlushesHeaders() + { + var emptyFilePath = Path.Combine(Environment.CurrentDirectory, "zz_" + Guid.NewGuid().ToString() + "EmptyTestFile.txt"); + var emptyFile = File.Create(emptyFilePath, 1024); + emptyFile.Close(); + + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + await context.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None); + Assert.True(context.Response.HasStartedSending); + await context.Response.Body.WriteAsync(new byte[10], 0, 10, CancellationToken.None); + context.Dispose(); + File.Delete(emptyFilePath); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + IEnumerable contentLength; + Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.HasValue); + Assert.Equal(10, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + [Fact] public async Task ResponseSendFile_ContentLength_PassedThrough() { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index 377bb51cbd..1d600fbd6b 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -30,7 +30,6 @@ namespace Microsoft.Net.Http.Server context.Dispose(); HttpResponseMessage response = await clientTask; Assert.Equal(200, (int)response.StatusCode); - Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); } } From 20f2219886f831bb234f11d6c09222e007d04b8e Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 12 Jun 2015 12:12:22 -0700 Subject: [PATCH 216/597] #121 Enable kernel mode response caching. --- .../FeatureContext.cs | 72 +- .../MessagePump.cs | 4 +- .../ServerInformation.cs | 6 + .../project.json | 1 + .../NativeInterop/UnsafeNativeMethods.cs | 17 +- .../RequestProcessing/Response.cs | 13 +- .../RequestProcessing/ResponseStream.cs | 2 +- .../ResponseCachingTests.cs | 225 ++++ ...soft.Net.Http.Server.FunctionalTests.xproj | 3 + .../ResponseCachingTests.cs | 1072 +++++++++++++++++ 10 files changed, 1410 insertions(+), 5 deletions(-) create mode 100644 test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs create mode 100644 test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 10401145c6..0d57f9c9ab 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -27,6 +27,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Server; using Microsoft.Net.WebSockets; @@ -46,8 +47,11 @@ namespace Microsoft.AspNet.Server.WebListener IHttpUpgradeFeature, IRequestIdentifierFeature { + private static Action OnStartDelegate = OnStart; + private RequestContext _requestContext; private FeatureCollection _features; + private bool _enableResponseCaching; private Stream _requestBody; private IDictionary _requestHeaders; @@ -69,11 +73,13 @@ namespace Microsoft.AspNet.Server.WebListener private Stream _responseStream; private IDictionary _responseHeaders; - internal FeatureContext(RequestContext requestContext) + internal FeatureContext(RequestContext requestContext, bool enableResponseCaching) { _requestContext = requestContext; _features = new FeatureCollection(); _authHandler = new AuthenticationHandler(requestContext); + _enableResponseCaching = enableResponseCaching; + requestContext.Response.OnSendingHeaders(OnStartDelegate, this); PopulateFeatures(); } @@ -471,5 +477,69 @@ namespace Microsoft.AspNet.Server.WebListener return _requestContext.TraceIdentifier; } } + + private static void OnStart(object obj) + { + var featureContext = (FeatureContext)obj; + + ConsiderEnablingResponseCache(featureContext); + } + + private static void ConsiderEnablingResponseCache(FeatureContext featureContext) + { + if (featureContext._enableResponseCaching) + { + // We don't have to worry too much about what Http.Sys supports, caching is a best-effort feature. + // If there's something about the request or response that prevents it from caching then the response + // will complete normally without caching. + featureContext._requestContext.Response.CacheTtl = GetCacheTtl(featureContext._requestContext); + } + } + + private static TimeSpan? GetCacheTtl(RequestContext requestContext) + { + var response = requestContext.Response; + // Only consider kernel-mode caching if the Cache-Control response header is present. + var cacheControlHeader = response.Headers[HeaderNames.CacheControl]; + if (string.IsNullOrEmpty(cacheControlHeader)) + { + return null; + } + + // Before we check the header value, check for the existence of other headers which would + // make us *not* want to cache the response. + if (response.Headers.ContainsKey(HeaderNames.SetCookie) + || response.Headers.ContainsKey(HeaderNames.Vary) + || response.Headers.ContainsKey(HeaderNames.Pragma)) + { + return null; + } + + // We require 'public' and 's-max-age' or 'max-age' or the Expires header. + CacheControlHeaderValue cacheControl; + if (CacheControlHeaderValue.TryParse(cacheControlHeader, out cacheControl) && cacheControl.Public) + { + if (cacheControl.SharedMaxAge.HasValue) + { + return cacheControl.SharedMaxAge; + } + else if (cacheControl.MaxAge.HasValue) + { + return cacheControl.MaxAge; + } + + DateTimeOffset expirationDate; + if (HeaderUtilities.TryParseDate(response.Headers[HeaderNames.Expires], out expirationDate)) + { + var expiresOffset = expirationDate - DateTimeOffset.UtcNow; + if (expiresOffset > TimeSpan.Zero) + { + return expiresOffset; + } + } + } + + return null; + } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index 7bfdaead54..9400c3fe48 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -78,6 +78,8 @@ namespace Microsoft.AspNet.Server.WebListener } } + internal bool EnableResponseCaching { get; set; } = true; + internal void Start(AppFunc app) { // Can't call Start twice @@ -160,7 +162,7 @@ namespace Microsoft.AspNet.Server.WebListener try { Interlocked.Increment(ref _outstandingRequests); - FeatureContext featureContext = new FeatureContext(requestContext); + FeatureContext featureContext = new FeatureContext(requestContext, EnableResponseCaching); await _appFunc(featureContext.Features).SupressContext(); requestContext.Dispose(); } diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs index 3ad2fbb2f4..9c50b466f8 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs @@ -50,5 +50,11 @@ namespace Microsoft.AspNet.Server.WebListener get { return _messagePump.MaxAccepts; } set { _messagePump.MaxAccepts = value; } } + + public bool EnableResponseCaching + { + get { return _messagePump.EnableResponseCaching; } + set { _messagePump.EnableResponseCaching = value; } + } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index d035af3107..0e52987ecb 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -5,6 +5,7 @@ "Microsoft.AspNet.Http.Features": "1.0.0-*", "Microsoft.AspNet.Hosting.Server.Abstractions": "1.0.0-*", "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", + "Microsoft.Net.Http.Headers": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*" }, "compilationOptions": { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index 7e48142209..2b2c05b6a3 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -212,7 +212,7 @@ namespace Microsoft.Net.Http.Server internal static extern uint HttpReceiveHttpRequest(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_REQUEST* pRequestBuffer, uint requestBufferLength, uint* pBytesReturned, SafeNativeOverlapped pOverlapped); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2* pHttpResponse, void* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); + internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2* pHttpResponse, HTTP_CACHE_POLICY* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK* pEntityChunks, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); @@ -369,6 +369,21 @@ namespace Microsoft.Net.Http.Server internal ushort* pQueryString; } + // Only cache unauthorized GETs + HEADs. + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_CACHE_POLICY + { + internal HTTP_CACHE_POLICY_TYPE Policy; + internal uint SecondsToLive; + } + + internal enum HTTP_CACHE_POLICY_TYPE : int + { + HttpCachePolicyNocache = 0, + HttpCachePolicyUserInvalidates = 1, + HttpCachePolicyTimeToLive = 2, + } + [StructLayout(LayoutKind.Sequential)] internal struct SOCKADDR { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index e33a031e5f..18da46bcbe 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -85,6 +85,7 @@ namespace Microsoft.Net.Http.Server _bufferingEnabled = _requestContext.Server.BufferResponses; _expectedBodyLength = 0; _nativeStream = null; + CacheTtl = null; } private enum ResponseState @@ -306,6 +307,8 @@ namespace Microsoft.Net.Http.Server get { return _responseState >= ResponseState.StartedSending; } } + public TimeSpan? CacheTtl { get; set; } + private void EnsureResponseStream() { if (_nativeStream == null) @@ -391,6 +394,14 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.pEntityChunks = null; } + var cachePolicy = new HttpApi.HTTP_CACHE_POLICY(); + var cacheTtl = CacheTtl; + if (cacheTtl.HasValue && cacheTtl.Value > TimeSpan.Zero) + { + cachePolicy.Policy = HttpApi.HTTP_CACHE_POLICY_TYPE.HttpCachePolicyTimeToLive; + cachePolicy.SecondsToLive = (uint)Math.Min(cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue); + } + byte[] reasonPhraseBytes = new byte[HeaderEncoding.GetByteCount(reasonPhrase)]; fixed (byte* pReasonPhrase = reasonPhraseBytes) { @@ -405,7 +416,7 @@ namespace Microsoft.Net.Http.Server Request.RequestId, (uint)flags, pResponse, - null, + &cachePolicy, &bytesSent, SafeLocalFree.Zero, 0, diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index c00c8af45f..6cc412dba5 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -583,7 +583,6 @@ namespace Microsoft.Net.Http.Server uint statusCode; uint bytesSent = 0; - flags |= _leftToWrite == count ? HttpApi.HTTP_FLAGS.NONE : HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; bool startedSending = _requestContext.Response.HasStartedSending; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, fileName, offset, count, chunked, cancellationRegistration); @@ -602,6 +601,7 @@ namespace Microsoft.Net.Http.Server bytesWritten = asyncResult.FileLength - offset; } // Update _leftToWrite now so we can queue up additional calls to SendFileAsync. + flags |= _leftToWrite == bytesWritten ? HttpApi.HTTP_FLAGS.NONE : HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; UpdateWritenCount((uint)bytesWritten); try diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs new file mode 100644 index 0000000000..3e44988bc6 --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Internal; +using Xunit; + +namespace Microsoft.AspNet.Server.WebListener.FunctionalTests +{ + public class ResponseCachingTests + { + [Fact] + public async Task Caching_NoCacheControl_NotCached() + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("2", await SendRequestAsync(address)); + } + } + + [Fact] + public async Task Caching_JustPublic_NotCached() + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Cache-Control"] = "public"; + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("2", await SendRequestAsync(address)); + } + } + + [Fact] + public async Task Caching_MaxAge_Cached() + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("1", await SendRequestAsync(address)); + } + } + + [Fact] + public async Task Caching_SMaxAge_Cached() + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Cache-Control"] = "public, s-maxage=10"; + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("1", await SendRequestAsync(address)); + } + } + + [Fact] + public async Task Caching_SMaxAgeAndMaxAge_SMaxAgePreferredCached() + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Cache-Control"] = "public, max-age=0, s-maxage=10"; + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("1", await SendRequestAsync(address)); + } + } + + [Fact] + public async Task Caching_Expires_Cached() + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Cache-Control"] = "public"; + httpContext.Response.Headers["Expires"] = (DateTime.UtcNow + TimeSpan.FromSeconds(10)).ToString("r"); + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("1", await SendRequestAsync(address)); + } + } + + [Theory] + [InlineData("Set-cookie")] + [InlineData("vary")] + [InlineData("pragma")] + public async Task Caching_DisallowedResponseHeaders_NotCached(string headerName) + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; + httpContext.Response.Headers[headerName] = "headerValue"; + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("2", await SendRequestAsync(address)); + } + } + + [Theory] + [InlineData("0")] + [InlineData("-1")] + public async Task Caching_InvalidExpires_NotCached(string expiresValue) + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Cache-Control"] = "public"; + httpContext.Response.Headers["Expires"] = expiresValue; + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("2", await SendRequestAsync(address)); + } + } + + [Fact] + public async Task Caching_ExpiresWithoutPublic_NotCached() + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Expires"] = (DateTime.UtcNow + TimeSpan.FromSeconds(10)).ToString("r"); + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("2", await SendRequestAsync(address)); + } + } + + [Fact] + public async Task Caching_MaxAgeAndExpires_MaxAgePreferred() + { + var requestCount = 1; + string address; + using (Utilities.CreateHttpServer(out address, env => + { + var httpContext = new DefaultHttpContext((IFeatureCollection)env); + httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching + httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; + httpContext.Response.Headers["Expires"] = (DateTime.UtcNow - TimeSpan.FromSeconds(10)).ToString("r"); // In the past + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + Assert.Equal("1", await SendRequestAsync(address)); + Assert.Equal("1", await SendRequestAsync(address)); + } + } + + private async Task SendRequestAsync(string uri) + { + using (var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) }) + { + var response = await client.GetAsync(uri); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(10, response.Content.Headers.ContentLength); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + return response.Headers.GetValues("x-request-count").FirstOrDefault(); + } + } + } +} diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj index 010e267757..185d583692 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj @@ -13,5 +13,8 @@ 2.0 + + + \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs new file mode 100644 index 0000000000..fca4fd66fc --- /dev/null +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -0,0 +1,1072 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Net.Http.Server.FunctionalTests +{ + public class ResponseCachingTests + { + private readonly string _absoluteFilePath; + private readonly long _fileLength; + + public ResponseCachingTests() + { + _absoluteFilePath = Directory.GetFiles(Environment.CurrentDirectory).First(); + _fileLength = new FileInfo(_absoluteFilePath).Length; + } + + [Fact] + public async Task Caching_SetTtlWithoutContentType_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_SetTtlWithContentType_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + // Http.Sys does not set the optional Age header for cached content. + // http://tools.ietf.org/html/rfc7234#section-5.1 + public async Task Caching_CheckAge_NotSentWithCachedContent() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + Assert.False(response.Headers.Age.HasValue); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + Assert.False(response.Headers.Age.HasValue); + } + } + + [Fact] + // Http.Sys does not update the optional Age header for cached content. + // http://tools.ietf.org/html/rfc7234#section-5.1 + public async Task Caching_SetAge_AgeHeaderCachedAndNotUpdated() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.Headers["age"] = "12345"; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + Assert.True(response.Headers.Age.HasValue); + Assert.Equal(TimeSpan.FromSeconds(12345), response.Headers.Age.Value); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + Assert.True(response.Headers.Age.HasValue); + Assert.Equal(TimeSpan.FromSeconds(12345), response.Headers.Age.Value); + } + } + + [Fact] + public async Task Caching_SetTtlZeroSeconds_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(0); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_SetTtlMiliseconds_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromMilliseconds(900); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_SetTtlNegative_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(-10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_SetTtlHuge_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.MaxValue; + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_SetTtlAndWriteBody_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Response.ShouldBuffer = true; + context.Response.Body.Write(new byte[10], 0, 10); + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_Flush_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Response.Body.Flush(); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_WriteFlush_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Response.Body.Write(new byte[10], 0, 10); + context.Response.Body.Flush(); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_WriteFullContentLength_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = 10; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Response.Body.Write(new byte[10], 0, 10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(10, response.Content.Headers.ContentLength); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(10, response.Content.Headers.ContentLength); + } + } + + [Fact] + public async Task Caching_SendFileNoContentLength_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + await context.Response.SendFileAsync(_absoluteFilePath, 0, null, CancellationToken.None); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(_fileLength, response.Content.Headers.ContentLength); + + responseTask = SendRequestAsync(address); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_SendFileWithFullContentLength_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength =_fileLength; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + await context.Response.SendFileAsync(_absoluteFilePath, 0, null, CancellationToken.None); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(_fileLength, response.Content.Headers.ContentLength); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(_fileLength, response.Content.Headers.ContentLength); + } + } + + [Fact] + public async Task Caching_SetTtlAndStatusCode_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + // Http.Sys will cache any status code. + for (int status = 200; status < 600; status++) + { + var responseTask = SendRequestAsync(address + status); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = status; + context.Response.Headers["x-request-count"] = status.ToString(); + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(status, (int)response.StatusCode); + Assert.Equal(status.ToString(), response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address + status); + Assert.Equal(status, (int)response.StatusCode); + Assert.Equal(status.ToString(), response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + } + + // Only GET requests can have cached responses. + [Theory] + // See HTTP_VERB for known verbs + [InlineData("HEAD")] + [InlineData("UNKNOWN")] + [InlineData("INVALID")] + [InlineData("OPTIONS")] + [InlineData("DELETE")] + [InlineData("TRACE")] + [InlineData("TRACK")] + [InlineData("MOVE")] + [InlineData("COPY")] + [InlineData("PROPFIND")] + [InlineData("PROPPATCH")] + [InlineData("MKCOL")] + [InlineData("LOCK")] + [InlineData("UNLOCK")] + [InlineData("SEARCH")] + [InlineData("CUSTOMVERB")] + [InlineData("PATCH")] + [InlineData("POST")] + [InlineData("PUT")] + // [InlineData("CONNECT", null)] 400 bad request if it's not a WebSocket handshake. + public async Task Caching_VariousUnsupportedRequestMethods_NotCached(string method) + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address, method); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = context.Request.Method + "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(method + "1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address, method); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = context.Request.Method + "2"; + // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(method + "2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // RFC violation. http://tools.ietf.org/html/rfc7234#section-4.4 + // "A cache MUST invalidate the effective Request URI ... when a non-error status code + // is received in response to an unsafe request method." + [Theory] + // See HTTP_VERB for known verbs + [InlineData("HEAD")] + [InlineData("UNKNOWN")] + [InlineData("INVALID")] + [InlineData("OPTIONS")] + [InlineData("DELETE")] + [InlineData("TRACE")] + [InlineData("TRACK")] + [InlineData("MOVE")] + [InlineData("COPY")] + [InlineData("PROPFIND")] + [InlineData("PROPPATCH")] + [InlineData("MKCOL")] + [InlineData("LOCK")] + [InlineData("UNLOCK")] + [InlineData("SEARCH")] + [InlineData("CUSTOMVERB")] + [InlineData("PATCH")] + [InlineData("POST")] + [InlineData("PUT")] + // [InlineData("CONNECT", null)] 400 bad request if it's not a WebSocket handshake. + public async Task Caching_UnsupportedRequestMethods_BypassCacheAndLeaveItIntact(string method) + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + // Cache the first response + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = context.Request.Method + "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("GET1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + // Try to clear the cache with a second request + responseTask = SendRequestAsync(address, method); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = context.Request.Method + "2"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Dispose(); + + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(method + "2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + // Send a third request to check the cache. + responseTask = SendRequestAsync(address); + + // The cache wasn't cleared when it should have been + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("GET1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // RFC violation / implementation limiation, Vary is not respected. + // http://tools.ietf.org/html/rfc7234#section-4.1 + [Fact] + public async Task Caching_SetVary_NotRespected() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address, "GET", "x-vary", "vary1"); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.Headers["vary"] = "x-vary"; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal("x-vary", response.Headers.GetValues("vary").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address, "GET", "x-vary", "vary2"); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal("x-vary", response.Headers.GetValues("vary").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // http://tools.ietf.org/html/rfc7234#section-3.2 + [Fact] + public async Task Caching_RequestAuthorization_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Dispose(); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_RequestAuthorization_NotServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); + + context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "2"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Dispose(); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // Responses can be cached for requests with Pragma: no-cache. + // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 + [Fact] + public async Task Caching_RequestPragmaNoCache_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address, "GET", "Pragma", "no-cache"); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // RFC violation, Requests with Pragma: no-cache should not be served from cache. + // http://tools.ietf.org/html/rfc7234#section-5.4 + // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 + [Fact] + public async Task Caching_RequestPragmaNoCache_NotRespectedAndServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + response = await SendRequestAsync(address, "GET", "Pragma", "no-cache"); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // Responses can be cached for requests with cache-control: no-cache. + // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 + [Fact] + public async Task Caching_RequestCacheControlNoCache_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address, "GET", "Cache-Control", "no-cache"); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // RFC violation, Requests with Cache-Control: no-cache should not be served from cache. + // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 + [Fact] + public async Task Caching_RequestCacheControlNoCache_NotRespectedAndServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + response = await SendRequestAsync(address, "GET", "Cache-Control", "no-cache"); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // RFC violation + // http://tools.ietf.org/html/rfc7234#section-5.2.1.1 + [Fact] + public async Task Caching_RequestCacheControlMaxAgeZero_NotRespectedAndServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + response = await SendRequestAsync(address, "GET", "Cache-Control", "min-fresh=0"); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // RFC violation + // http://tools.ietf.org/html/rfc7234#section-5.2.1.3 + [Fact] + public async Task Caching_RequestCacheControlMinFreshOutOfRange_NotRespectedAndServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + response = await SendRequestAsync(address, "GET", "Cache-Control", "min-fresh=20"); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + + // Http.Sys limitation, partial responses are not cached. + [Fact] + public async Task Caching_CacheRange_NotCached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address, "GET", "Range", "bytes=0-10"); + + var context = await server.GetContextAsync(); + context.Response.StatusCode = 206; + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.Headers["content-range"] = "bytes 0-10/100"; + context.Response.ContentLength = 11; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Response.Body.Write(new byte[100], 0, 11); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(206, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[11], await response.Content.ReadAsByteArrayAsync()); + + responseTask = SendRequestAsync(address, "GET", "Range", "bytes=0-10"); + + context = await server.GetContextAsync(); + context.Response.StatusCode = 206; + context.Response.Headers["x-request-count"] = "2"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.Headers["content-range"] = "bytes 0-10/100"; + context.Response.ContentLength = 11; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Response.Body.Write(new byte[100], 0, 11); + context.Dispose(); + + response = await responseTask; + Assert.Equal(206, (int)response.StatusCode); + Assert.Equal("2", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal("bytes 0-10/100", response.Content.Headers.GetValues("content-range").FirstOrDefault()); + Assert.Equal(new byte[11], await response.Content.ReadAsByteArrayAsync()); + } + } + + // http://tools.ietf.org/html/rfc7233#section-4.1 + [Fact] + public async Task Caching_RequestRangeFromCache_RangeServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = 100; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Response.Body.Write(new byte[100], 0, 100); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[100], await response.Content.ReadAsByteArrayAsync()); + + response = await SendRequestAsync(address, "GET", "Range", "bytes=0-10"); + Assert.Equal(206, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal("bytes 0-10/100", response.Content.Headers.GetValues("content-range").FirstOrDefault()); + Assert.Equal(new byte[11], await response.Content.ReadAsByteArrayAsync()); + } + } + + // http://tools.ietf.org/html/rfc7233#section-4.1 + [Fact] + public async Task Caching_RequestMultipleRangesFromCache_RangesServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = 100; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Response.Body.Write(new byte[100], 0, 100); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[100], await response.Content.ReadAsByteArrayAsync()); + + response = await SendRequestAsync(address, "GET", "Range", "bytes=0-10,15-20"); + Assert.Equal(206, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.True(response.Content.Headers.GetValues("content-type").First().StartsWith("multipart/byteranges;")); + } + } + + [Fact] + public async Task Caching_RequestRangeFromCachedFile_ServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseLength = _fileLength / 2; // Make sure it handles partial files. + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = responseLength; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + await context.Response.SendFileAsync(_absoluteFilePath, 0, responseLength, CancellationToken.None); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(responseLength, response.Content.Headers.ContentLength); + + // Send a second request and make sure we get the same response (without listening for one on the server). + var rangeLength = responseLength / 2; + response = await SendRequestAsync(address, "GET", "Range", "bytes=0-" + (rangeLength - 1)); + Assert.Equal(206, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(rangeLength, response.Content.Headers.ContentLength); + Assert.Equal("bytes 0-" + (rangeLength - 1) + "/" + responseLength, response.Content.Headers.GetValues("content-range").FirstOrDefault()); + } + } + + [Fact] + public async Task Caching_RequestMultipleRangesFromCachedFile_ServedFromCache() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseLength = _fileLength / 2; // Make sure it handles partial files. + var responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = responseLength; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + await context.Response.SendFileAsync(_absoluteFilePath, 0, responseLength, CancellationToken.None); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(responseLength, response.Content.Headers.ContentLength); + + // Send a second request and make sure we get the same response (without listening for one on the server). + var rangeLength = responseLength / 4; + response = await SendRequestAsync(address, "GET", "Range", "bytes=0-" + (rangeLength - 1) + "," + rangeLength + "-" + (rangeLength + rangeLength - 1)); + Assert.Equal(206, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.True(response.Content.Headers.GetValues("content-type").First().StartsWith("multipart/byteranges;")); + } + } + + private async Task SendRequestAsync(string uri, string method = "GET", string extraHeader = null, string extraHeaderValue = null) + { + using (var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) }) + { + var request = new HttpRequestMessage(new HttpMethod(method), uri); + if (!string.IsNullOrEmpty(extraHeader)) + { + request.Headers.Add(extraHeader, extraHeaderValue); + } + return await client.SendAsync(request); + } + } + } +} From fa3b98f1137e7f8f66b8fecaa96078ac1fa996bf Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 12 Jun 2015 15:28:54 -0700 Subject: [PATCH 217/597] React to OnSendingHeaders rename. --- .../FeatureContext.cs | 8 ++++---- .../RequestProcessing/Response.cs | 12 ++++++------ .../ResponseHeaderTests.cs | 8 ++++---- .../ResponseTests.cs | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 0d57f9c9ab..0994bde446 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -79,7 +79,7 @@ namespace Microsoft.AspNet.Server.WebListener _features = new FeatureCollection(); _authHandler = new AuthenticationHandler(requestContext); _enableResponseCaching = enableResponseCaching; - requestContext.Response.OnSendingHeaders(OnStartDelegate, this); + requestContext.Response.OnResponseStarting(OnStartDelegate, this); PopulateFeatures(); } @@ -372,14 +372,14 @@ namespace Microsoft.AspNet.Server.WebListener set { _responseHeaders = value; } } - bool IHttpResponseFeature.HeadersSent + bool IHttpResponseFeature.HasStarted { get { return Response.HasStarted; } } - void IHttpResponseFeature.OnSendingHeaders(Action callback, object state) + void IHttpResponseFeature.OnResponseStarting(Action callback, object state) { - Response.OnSendingHeaders(callback, state); + Response.OnResponseStarting(callback, state); } void IHttpResponseFeature.OnResponseCompleted(Action callback, object state) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 18da46bcbe..18e44a4cd2 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -48,7 +48,7 @@ namespace Microsoft.Net.Http.Server private long _expectedBodyLength; private BoundaryType _boundaryType; private HttpApi.HTTP_RESPONSE_V2 _nativeResponse; - private IList, object>> _onSendingHeadersActions; + private IList, object>> _onResponseStartingActions; private IList, object>> _onResponseCompletedActions; private RequestContext _requestContext; @@ -80,7 +80,7 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.Version.MajorVersion = 1; _nativeResponse.Response_V1.Version.MinorVersion = 1; _responseState = ResponseState.Created; - _onSendingHeadersActions = new List, object>>(); + _onResponseStartingActions = new List, object>>(); _onResponseCompletedActions = new List, object>>(); _bufferingEnabled = _requestContext.Server.BufferResponses; _expectedBodyLength = 0; @@ -778,12 +778,12 @@ namespace Microsoft.Net.Http.Server _nativeStream.SwitchToOpaqueMode(); } - public void OnSendingHeaders(Action callback, object state) + public void OnResponseStarting(Action callback, object state) { - IList, object>> actions = _onSendingHeadersActions; + IList, object>> actions = _onResponseStartingActions; if (actions == null) { - throw new InvalidOperationException("Headers already sent"); + throw new InvalidOperationException("Response already started"); } actions.Add(new Tuple, object>(callback, state)); @@ -802,7 +802,7 @@ namespace Microsoft.Net.Http.Server private void NotifyOnSendingHeaders() { - var actions = Interlocked.Exchange(ref _onSendingHeadersActions, null); + var actions = Interlocked.Exchange(ref _onResponseStartingActions, null); if (actions == null) { // Something threw the first time, do not try again. diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 5d7cc5234a..cbf7e8ca3f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -216,9 +216,9 @@ namespace Microsoft.AspNet.Server.WebListener responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); var body = responseInfo.Body; - Assert.False(responseInfo.HeadersSent); + Assert.False(responseInfo.HasStarted); body.Flush(); - Assert.True(responseInfo.HeadersSent); + Assert.True(responseInfo.HasStarted); Assert.Throws(() => responseInfo.StatusCode = 404); Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); return Task.FromResult(0); @@ -248,9 +248,9 @@ namespace Microsoft.AspNet.Server.WebListener responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); var body = responseInfo.Body; - Assert.False(responseInfo.HeadersSent); + Assert.False(responseInfo.HasStarted); await body.FlushAsync(); - Assert.True(responseInfo.HeadersSent); + Assert.True(responseInfo.HasStarted); Assert.Throws(() => responseInfo.StatusCode = 404); Assert.Throws(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" })); })) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index eaafe14c21..9767fe11bf 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); Assert.Equal(200, httpContext.Response.StatusCode); - Assert.False(httpContext.Response.HeadersSent); + Assert.False(httpContext.Response.HasStarted); return Task.FromResult(0); })) { From cdf8072c8355e216cac7edc970a2d473850fa288 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 16 Jun 2015 15:59:30 -0700 Subject: [PATCH 218/597] #127 Target net451 and use Marshal.SizeOf. --- .../AuthenticationManager.cs | 5 ---- .../RequestProcessing/Response.cs | 7 +----- .../TimeoutManager.cs | 6 +---- src/Microsoft.Net.Http.Server/WebListener.cs | 24 ++----------------- src/Microsoft.Net.Http.Server/project.json | 2 +- .../WebSocketBuffer.cs | 5 ---- src/Microsoft.Net.WebSockets/project.json | 3 ++- 7 files changed, 7 insertions(+), 45 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index ea67513993..76377dd63c 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -38,13 +38,8 @@ namespace Microsoft.Net.Http.Server /// public sealed class AuthenticationManager { -#if DNXCORE50 private static readonly int AuthInfoSize = Marshal.SizeOf(); -#else - private static readonly int AuthInfoSize = - Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO)); -#endif private WebListener _server; private AuthenticationSchemes _authSchemes; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 18e44a4cd2..17ad8688ed 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -667,12 +667,7 @@ namespace Microsoft.Net.Http.Server } knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; - knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = -#if DNXCORE50 - (uint)Marshal.SizeOf(); -#else - (uint)Marshal.SizeOf(typeof(HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); -#endif + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf(); HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index 6ef2ca5b7a..9f1ba26423 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -35,13 +35,9 @@ namespace Microsoft.Net.Http.Server /// public sealed class TimeoutManager { -#if DNXCORE50 private static readonly int TimeoutLimitSize = Marshal.SizeOf(); -#else - private static readonly int TimeoutLimitSize = - Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO)); -#endif + private WebListener _server; private int[] _timeouts; private uint _minSendBytesPerSecond; diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index fa8099e275..c0e4d0676b 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -41,18 +41,10 @@ namespace Microsoft.Net.Http.Server public sealed class WebListener : IDisposable { private const long DefaultRequestQueueLength = 1000; // Http.sys default. -#if DNXCORE50 private static readonly int RequestChannelBindStatusSize = Marshal.SizeOf(); private static readonly int BindingInfoSize = Marshal.SizeOf(); -#else - private static readonly Type ChannelBindingStatusType = typeof(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS); - private static readonly int RequestChannelBindStatusSize = - Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS)); - private static readonly int BindingInfoSize = - Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO)); -#endif // Win8# 559317 fixed a bug in Http.sys's HttpReceiveClientCertificate method. // Without this fix IOCP callbacks were not being called although ERROR_IO_PENDING was @@ -244,7 +236,7 @@ namespace Microsoft.Net.Http.Server long length = _requestQueueLength.Value; uint result = UnsafeNclNativeMethods.HttpApi.HttpSetRequestQueueProperty(_requestQueueHandle, UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, - new IntPtr((void*)&length), (uint)Marshal.SizeOf(length), 0, IntPtr.Zero); + new IntPtr((void*)&length), (uint)Marshal.SizeOf(), 0, IntPtr.Zero); if (result != 0) { @@ -766,11 +758,7 @@ namespace Microsoft.Net.Http.Server knownHeaderInfo[httpResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[httpResponse.ResponseInfoCount].Length = -#if DNXCORE50 - (uint)Marshal.SizeOf(); -#else - (uint)Marshal.SizeOf(typeof(UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS)); -#endif + (uint)Marshal.SizeOf(); UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); @@ -858,11 +846,7 @@ namespace Microsoft.Net.Http.Server private static int GetTokenOffsetFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); -#if DNXCORE50 IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); -#else - IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelToken")); -#endif Debug.Assert(tokenPointer != IntPtr.Zero); return (int)IntPtrHelper.Subtract(tokenPointer, blob); } @@ -870,11 +854,7 @@ namespace Microsoft.Net.Http.Server private static int GetTokenSizeFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); -#if DNXCORE50 return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); -#else - return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf(ChannelBindingStatusType, "ChannelTokenSize")); -#endif } internal ChannelBinding GetChannelBinding(ulong connectionId, bool isSecureConnection) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 5e7160e13d..4859950613 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -9,7 +9,7 @@ "allowUnsafe": true }, "frameworks": { - "net45": { }, + "net451": { }, "dnx451": { }, "dnxcore50": { "dependencies": { diff --git a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs index 8230117bc6..e71d463f7f 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs @@ -50,13 +50,8 @@ namespace Microsoft.Net.WebSockets public const int MinSendBufferSize = 16; internal const int MinReceiveBufferSize = 256; internal const int MaxBufferSize = 64 * 1024; -#if DNXCORE50 private static readonly int SizeOfUInt = Marshal.SizeOf(); private static readonly int SizeOfBool = Marshal.SizeOf(); -#else - private static readonly int SizeOfUInt = Marshal.SizeOf(typeof(uint)); - private static readonly int SizeOfBool = Marshal.SizeOf(typeof(bool)); -#endif private static readonly int PropertyBufferSize = (2 * SizeOfUInt) + SizeOfBool + IntPtr.Size; private readonly int _ReceiveBufferSize; diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 9c05f0f4b9..50fa32a2e1 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -5,7 +5,8 @@ }, "compilationOptions": { "allowUnsafe": true }, "frameworks": { - "net45": { }, + "net451": { }, + "dnx451": { }, "dnxcore50": { "dependencies": { "System.Collections": "4.0.10-beta-*", From 03f7e4b36236c0d3669f0699dc479fee48b2e9b1 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 18 Jun 2015 15:55:12 -0700 Subject: [PATCH 219/597] React to IRequestIdentifierFeature refactor. --- .../FeatureContext.cs | 14 ++++++++++---- .../RequestTests.cs | 6 +++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 0994bde446..80f8d86f24 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Server.WebListener IHttpWebSocketFeature, IHttpAuthenticationFeature, IHttpUpgradeFeature, - IRequestIdentifierFeature + IHttpRequestIdentifierFeature { private static Action OnStartDelegate = OnStart; @@ -66,6 +66,7 @@ namespace Microsoft.AspNet.Server.WebListener private int? _remotePort; private int? _localPort; private bool? _isLocal; + private string _requestId; private X509Certificate2 _clientCert; private ClaimsPrincipal _user; private IAuthenticationHandler _authHandler; @@ -107,7 +108,7 @@ namespace Microsoft.AspNet.Server.WebListener _features.Add(typeof(IHttpBufferingFeature), this); _features.Add(typeof(IHttpRequestLifetimeFeature), this); _features.Add(typeof(IHttpAuthenticationFeature), this); - _features.Add(typeof(IRequestIdentifierFeature), this); + _features.Add(typeof(IHttpRequestIdentifierFeature), this); if (Request.IsSecureConnection) { @@ -470,12 +471,17 @@ namespace Microsoft.AspNet.Server.WebListener set { _authHandler = value; } } - Guid IRequestIdentifierFeature.TraceIdentifier + string IHttpRequestIdentifierFeature.TraceIdentifier { get { - return _requestContext.TraceIdentifier; + if (_requestId == null) + { + _requestId = _requestContext.TraceIdentifier.ToString(); + } + return _requestId; } + set { _requestId = value; } } private static void OnStart(object obj) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index bb005a0e22..72bd8ead4d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.True(connectionInfo.IsLocal); // Trace identifier - var requestIdentifierFeature = httpContext.GetFeature(); + var requestIdentifierFeature = httpContext.GetFeature(); Assert.NotNull(requestIdentifierFeature); Assert.NotNull(requestIdentifierFeature.TraceIdentifier); @@ -100,7 +100,7 @@ namespace Microsoft.AspNet.Server.WebListener { var requestInfo = httpContext.GetFeature(); var connectionInfo = httpContext.GetFeature(); - var requestIdentifierFeature = httpContext.GetFeature(); + var requestIdentifierFeature = httpContext.GetFeature(); // Request Keys Assert.Equal("http", requestInfo.Scheme); @@ -145,7 +145,7 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); var requestInfo = httpContext.GetFeature(); - var requestIdentifierFeature = httpContext.GetFeature(); + var requestIdentifierFeature = httpContext.GetFeature(); try { Assert.Equal(expectedPath, requestInfo.Path); From 41dba1fea1dab68de4b8200fc34b0fdd58308abf Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 23 Jun 2015 11:43:31 -0700 Subject: [PATCH 220/597] Change hardcoded `bash` shebang to `env` - aspnet/Home#695 - support various `bash` installation locations - in particular, enable building on FreeBSD --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index d81164353c..3ef874f9bd 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild From 38f70a02f73cd2b7553acfe9fc0391c616e8942d Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 19 Jun 2015 12:14:13 -0700 Subject: [PATCH 221/597] #125 Add a Hosting dependency and Program.Main. --- samples/HotAddSample/project.json | 3 +- samples/SelfHostServer/project.json | 3 +- .../Program.cs | 45 +++++++++++++++++++ .../project.json | 4 +- .../project.json | 1 - 5 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/Program.cs diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index cfc1678585..35533a5c39 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,12 +1,11 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.Framework.Logging.Console": "1.0.0-*" }, "commands": { - "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:12345" + "web": "Microsoft.AspNet.Server.WebListener --server.urls http://localhost:12345" }, "frameworks" : { "dnx451" : { }, diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index d8a3b0a190..cf63300858 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,10 +1,9 @@ { "dependencies": { - "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.Framework.Logging.Console": "1.0.0-*" }, - "commands": { "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:8080" }, + "commands": { "web": "Microsoft.AspNet.Server.WebListener --server.urls http://localhost:8080" }, "frameworks": { "dnx451": { }, "dnxcore50": { } diff --git a/src/Microsoft.AspNet.Server.WebListener/Program.cs b/src/Microsoft.AspNet.Server.WebListener/Program.cs new file mode 100644 index 0000000000..ef795cbef0 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/Program.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.Linq; + +namespace Microsoft.AspNet.Server.WebListener +{ + public class Program + { + private readonly IServiceProvider _serviceProvider; + + public Program(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public void Main(string[] args) + { + var program = new Hosting.Program(_serviceProvider); + var mergedArgs = new[] { "--server", "Microsoft.AspNet.Server.WebListener" }.Concat(args).ToArray(); + program.Main(mergedArgs); + } + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 0e52987ecb..d2f2494450 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -2,9 +2,7 @@ "version": "1.0.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { - "Microsoft.AspNet.Http.Features": "1.0.0-*", - "Microsoft.AspNet.Hosting.Server.Abstractions": "1.0.0-*", - "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", + "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.Net.Http.Headers": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*" }, diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 310ae5d0f1..1edc19d889 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -3,7 +3,6 @@ "test": "xunit.runner.aspnet" }, "dependencies": { - "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" From 7b31e034ca7ee952a1d5bdef5956bcc1493df6c8 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Thu, 25 Jun 2015 17:10:13 -0700 Subject: [PATCH 222/597] React to Http changes --- .../AuthenticationHandler.cs | 21 +++++++-------- .../FeatureContext.cs | 9 ++++--- .../RequestProcessing/Response.cs | 18 ++++++------- .../AuthenticationTests.cs | 26 +++++++------------ 4 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index 5f0515d3ae..225d45a388 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -43,14 +43,14 @@ namespace Microsoft.AspNet.Server.WebListener _customChallenges = AuthenticationSchemes.None; } - public void Authenticate(AuthenticateContext context) + public Task AuthenticateAsync(AuthenticateContext context) { var user = _requestContext.User; var identity = user == null ? null : (ClaimsIdentity)user.Identity; foreach (var authType in ListEnabledAuthSchemes()) { - string authScheme = authType.ToString(); + var authScheme = authType.ToString(); if (string.Equals(authScheme, context.AuthenticationScheme, StringComparison.Ordinal)) { if (identity != null && identity.IsAuthenticated @@ -64,29 +64,26 @@ namespace Microsoft.AspNet.Server.WebListener } } } - } - - public Task AuthenticateAsync(AuthenticateContext context) - { - Authenticate(context); return Task.FromResult(0); } - public void Challenge(ChallengeContext context) + public Task ChallengeAsync(ChallengeContext context) { foreach (var scheme in ListEnabledAuthSchemes()) { var authScheme = scheme.ToString(); // Not including any auth types means it's a blanket challenge for any auth type. - if (context.AuthenticationScheme == null || + if (context.AuthenticationScheme == string.Empty || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) { + _requestContext.Response.StatusCode = 401; _customChallenges |= scheme; context.Accept(); } } // A challenge was issued, it overrides any pre-set auth types. _requestContext.AuthenticationChallenges = _customChallenges; + return Task.FromResult(0); } public void GetDescriptions(DescribeSchemesContext context) @@ -98,14 +95,16 @@ namespace Microsoft.AspNet.Server.WebListener } } - public void SignIn(SignInContext context) + public Task SignInAsync(SignInContext context) { // Not supported + return Task.FromResult(0); } - public void SignOut(SignOutContext context) + public Task SignOutAsync(SignOutContext context) { // Not supported + return Task.FromResult(0); } private IDictionary GetDescription(string authenticationScheme) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 80f8d86f24..e113cc0f34 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Server.WebListener IHttpUpgradeFeature, IHttpRequestIdentifierFeature { - private static Action OnStartDelegate = OnStart; + private static Func OnStartDelegate = OnStart; private RequestContext _requestContext; private FeatureCollection _features; @@ -378,12 +378,12 @@ namespace Microsoft.AspNet.Server.WebListener get { return Response.HasStarted; } } - void IHttpResponseFeature.OnResponseStarting(Action callback, object state) + void IHttpResponseFeature.OnResponseStarting(Func callback, object state) { Response.OnResponseStarting(callback, state); } - void IHttpResponseFeature.OnResponseCompleted(Action callback, object state) + void IHttpResponseFeature.OnResponseCompleted(Func callback, object state) { Response.OnResponseCompleted(callback, state); } @@ -484,11 +484,12 @@ namespace Microsoft.AspNet.Server.WebListener set { _requestId = value; } } - private static void OnStart(object obj) + private static Task OnStart(object obj) { var featureContext = (FeatureContext)obj; ConsiderEnablingResponseCache(featureContext); + return Task.FromResult(0); } private static void ConsiderEnablingResponseCache(FeatureContext featureContext) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 17ad8688ed..65a6442e6e 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -48,8 +48,8 @@ namespace Microsoft.Net.Http.Server private long _expectedBodyLength; private BoundaryType _boundaryType; private HttpApi.HTTP_RESPONSE_V2 _nativeResponse; - private IList, object>> _onResponseStartingActions; - private IList, object>> _onResponseCompletedActions; + private IList, object>> _onResponseStartingActions; + private IList, object>> _onResponseCompletedActions; private RequestContext _requestContext; private bool _bufferingEnabled; @@ -80,8 +80,8 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.Version.MajorVersion = 1; _nativeResponse.Response_V1.Version.MinorVersion = 1; _responseState = ResponseState.Created; - _onResponseStartingActions = new List, object>>(); - _onResponseCompletedActions = new List, object>>(); + _onResponseStartingActions = new List, object>>(); + _onResponseCompletedActions = new List, object>>(); _bufferingEnabled = _requestContext.Server.BufferResponses; _expectedBodyLength = 0; _nativeStream = null; @@ -773,18 +773,18 @@ namespace Microsoft.Net.Http.Server _nativeStream.SwitchToOpaqueMode(); } - public void OnResponseStarting(Action callback, object state) + public void OnResponseStarting(Func callback, object state) { - IList, object>> actions = _onResponseStartingActions; + var actions = _onResponseStartingActions; if (actions == null) { throw new InvalidOperationException("Response already started"); } - actions.Add(new Tuple, object>(callback, state)); + actions.Add(new Tuple, object>(callback, state)); } - public void OnResponseCompleted(Action callback, object state) + public void OnResponseCompleted(Func callback, object state) { var actions = _onResponseCompletedActions; if (actions == null) @@ -792,7 +792,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException("Response already completed"); } - actions.Add(new Tuple, object>(callback, state)); + actions.Add(new Tuple, object>(callback, state)); } private void NotifyOnSendingHeaders() diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index cf0fb50a39..f802a8d3bb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -256,17 +256,16 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, async env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); foreach (var scheme in authTypeList) { - var authResults = context.Authentication.Authenticate(scheme); + var authResults = await context.Authentication.AuthenticateAsync(scheme); Assert.Null(authResults); } - return Task.FromResult(0); })) { var response = await SendRequestAsync(address); @@ -286,7 +285,7 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType, out address, env => + using (Utilities.CreateHttpAuthServer(authType, out address, async env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); @@ -294,14 +293,13 @@ namespace Microsoft.AspNet.Server.WebListener var count = 0; foreach (var scheme in authTypeList) { - var authResults = context.Authentication.Authenticate(scheme); + var authResults = await context.Authentication.AuthenticateAsync(scheme); if (authResults != null) { count++; } } Assert.Equal(1, count); - return Task.FromResult(0); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); @@ -325,8 +323,7 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - context.Authentication.Challenge(); - return Task.FromResult(0); + return context.Authentication.ChallengeAsync(); })) { var response = await SendRequestAsync(address); @@ -346,16 +343,15 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, async env => { var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); foreach (var scheme in authTypeList) { - context.Authentication.Challenge(scheme); + await context.Authentication.ChallengeAsync(scheme); } - return Task.FromResult(0); })) { var response = await SendRequestAsync(address); @@ -379,8 +375,7 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - context.Authentication.Challenge(authType.ToString()); - return Task.FromResult(0); + return context.Authentication.ChallengeAsync(authType.ToString()); })) { var response = await SendRequestAsync(address); @@ -407,12 +402,11 @@ namespace Microsoft.AspNet.Server.WebListener var context = new DefaultHttpContext((IFeatureCollection)env); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - Assert.Throws(() => context.Authentication.Challenge(authType.ToString())); - return Task.FromResult(0); + return Assert.ThrowsAsync(() => context.Authentication.ChallengeAsync(authType.ToString())); })) { var response = await SendRequestAsync(address); - Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(0, response.Headers.WwwAuthenticate.Count); } } From e825da09106b804104cff7d00509ec7f76d00698 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Thu, 25 Jun 2015 17:20:42 -0700 Subject: [PATCH 223/597] Fix build --- .../FeatureContext.cs | 10 ++++----- .../RequestProcessing/Response.cs | 22 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index e113cc0f34..c4285957cf 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Server.WebListener _features = new FeatureCollection(); _authHandler = new AuthenticationHandler(requestContext); _enableResponseCaching = enableResponseCaching; - requestContext.Response.OnResponseStarting(OnStartDelegate, this); + requestContext.Response.OnStarting(OnStartDelegate, this); PopulateFeatures(); } @@ -378,14 +378,14 @@ namespace Microsoft.AspNet.Server.WebListener get { return Response.HasStarted; } } - void IHttpResponseFeature.OnResponseStarting(Func callback, object state) + void IHttpResponseFeature.OnStarting(Func callback, object state) { - Response.OnResponseStarting(callback, state); + Response.OnStarting(callback, state); } - void IHttpResponseFeature.OnResponseCompleted(Func callback, object state) + void IHttpResponseFeature.OnCompleted(Func callback, object state) { - Response.OnResponseCompleted(callback, state); + Response.OnCompleted(callback, state); } string IHttpResponseFeature.ReasonPhrase diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 65a6442e6e..487aa46cdc 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -48,8 +48,8 @@ namespace Microsoft.Net.Http.Server private long _expectedBodyLength; private BoundaryType _boundaryType; private HttpApi.HTTP_RESPONSE_V2 _nativeResponse; - private IList, object>> _onResponseStartingActions; - private IList, object>> _onResponseCompletedActions; + private IList, object>> _onStartingActions; + private IList, object>> _onCompletedActions; private RequestContext _requestContext; private bool _bufferingEnabled; @@ -80,8 +80,8 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.Version.MajorVersion = 1; _nativeResponse.Response_V1.Version.MinorVersion = 1; _responseState = ResponseState.Created; - _onResponseStartingActions = new List, object>>(); - _onResponseCompletedActions = new List, object>>(); + _onStartingActions = new List, object>>(); + _onCompletedActions = new List, object>>(); _bufferingEnabled = _requestContext.Server.BufferResponses; _expectedBodyLength = 0; _nativeStream = null; @@ -773,9 +773,9 @@ namespace Microsoft.Net.Http.Server _nativeStream.SwitchToOpaqueMode(); } - public void OnResponseStarting(Func callback, object state) + public void OnStarting(Func callback, object state) { - var actions = _onResponseStartingActions; + var actions = _onStartingActions; if (actions == null) { throw new InvalidOperationException("Response already started"); @@ -784,9 +784,9 @@ namespace Microsoft.Net.Http.Server actions.Add(new Tuple, object>(callback, state)); } - public void OnResponseCompleted(Func callback, object state) + public void OnCompleted(Func callback, object state) { - var actions = _onResponseCompletedActions; + var actions = _onCompletedActions; if (actions == null) { throw new InvalidOperationException("Response already completed"); @@ -797,7 +797,7 @@ namespace Microsoft.Net.Http.Server private void NotifyOnSendingHeaders() { - var actions = Interlocked.Exchange(ref _onResponseStartingActions, null); + var actions = Interlocked.Exchange(ref _onStartingActions, null); if (actions == null) { // Something threw the first time, do not try again. @@ -813,7 +813,7 @@ namespace Microsoft.Net.Http.Server private void NotifyOnResponseCompleted() { - var actions = Interlocked.Exchange(ref _onResponseCompletedActions, null); + var actions = Interlocked.Exchange(ref _onCompletedActions, null); if (actions == null) { // Something threw the first time, do not try again. @@ -829,7 +829,7 @@ namespace Microsoft.Net.Http.Server catch (Exception ex) { RequestContext.Logger.LogWarning( - String.Format(Resources.Warning_ExceptionInOnResponseCompletedAction, nameof(OnResponseCompleted)), + String.Format(Resources.Warning_ExceptionInOnResponseCompletedAction, nameof(OnCompleted)), ex); } } From 2b5785c2c6fb44f0da920378b417dcd4359bb87a Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 1 Jul 2015 10:35:10 -0700 Subject: [PATCH 224/597] #131 Handle behavioral challenges (403 vs 401). --- .../AuthenticationHandler.cs | 43 ++++++++--- .../AuthenticationTests.cs | 73 +++++++++++++++++++ 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index 225d45a388..aa0e411d72 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -45,8 +45,7 @@ namespace Microsoft.AspNet.Server.WebListener public Task AuthenticateAsync(AuthenticateContext context) { - var user = _requestContext.User; - var identity = user == null ? null : (ClaimsIdentity)user.Identity; + var identity = (ClaimsIdentity)_requestContext.User?.Identity; foreach (var authType in ListEnabledAuthSchemes()) { @@ -56,7 +55,7 @@ namespace Microsoft.AspNet.Server.WebListener if (identity != null && identity.IsAuthenticated && string.Equals(authScheme, identity.AuthenticationType, StringComparison.Ordinal)) { - context.Authenticated(new ClaimsPrincipal(user.Identity), properties: null, description: GetDescription(authScheme)); + context.Authenticated(new ClaimsPrincipal(identity), properties: null, description: GetDescription(authScheme)); } else { @@ -73,12 +72,38 @@ namespace Microsoft.AspNet.Server.WebListener { var authScheme = scheme.ToString(); // Not including any auth types means it's a blanket challenge for any auth type. - if (context.AuthenticationScheme == string.Empty || + if (string.IsNullOrEmpty(context.AuthenticationScheme) || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) { - _requestContext.Response.StatusCode = 401; - _customChallenges |= scheme; - context.Accept(); + switch (context.Behavior) + { + case ChallengeBehavior.Forbidden: + _requestContext.Response.StatusCode = 403; + context.Accept(); + break; + case ChallengeBehavior.Unauthorized: + _requestContext.Response.StatusCode = 401; + _customChallenges |= scheme; + context.Accept(); + break; + case ChallengeBehavior.Automatic: + var identity = (ClaimsIdentity)_requestContext.User?.Identity; + if (identity != null && identity.IsAuthenticated + && string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal)) + { + _requestContext.Response.StatusCode = 403; + context.Accept(); + } + else + { + _requestContext.Response.StatusCode = 401; + _customChallenges |= scheme; + context.Accept(); + } + break; + default: + throw new NotSupportedException(context.Behavior.ToString()); + } } } // A challenge was issued, it overrides any pre-set auth types. @@ -97,13 +122,13 @@ namespace Microsoft.AspNet.Server.WebListener public Task SignInAsync(SignInContext context) { - // Not supported + // Not supported. AuthenticationManager will throw if !Accepted. return Task.FromResult(0); } public Task SignOutAsync(SignOutContext context) { - // Not supported + // Not supported. AuthenticationManager will throw if !Accepted. return Task.FromResult(0); } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index f802a8d3bb..56478fc87f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -21,6 +21,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Features.Authentication; using Microsoft.AspNet.Http.Internal; using Xunit; using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes; @@ -411,6 +412,78 @@ namespace Microsoft.AspNet.Server.WebListener } } + [Theory] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] + [InlineData(AuthenticationSchemes.Basic)] + public async Task AuthTypes_Forbid_Forbidden(AuthenticationSchemes authType) + { + string address; + var authTypes = AuthenticationSchemes.AllowAnonymous | AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; + using (Utilities.CreateHttpAuthServer(authTypes, out address, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + return context.Authentication.ForbidAsync(authType.ToString()); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + } + } + + [Theory] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // Not implemented + // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials + public async Task AuthTypes_ChallengeAuthenticatedAuthType_Forbidden(AuthenticationSchemes authType) + { + string address; + using (Utilities.CreateHttpAuthServer(authType, out address, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + return context.Authentication.ChallengeAsync(authType.ToString()); + })) + { + var response = await SendRequestAsync(address, useDefaultCredentials: true); + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + // for some reason Kerberos and Negotiate include a 2nd stage challenge. + // Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + } + } + + [Theory] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // Not implemented + // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials + public async Task AuthTypes_UnathorizedAuthenticatedAuthType_Unauthorized(AuthenticationSchemes authType) + { + string address; + using (Utilities.CreateHttpAuthServer(authType, out address, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + return context.Authentication.ChallengeAsync(authType.ToString(), null, ChallengeBehavior.Unauthorized); + })) + { + var response = await SendRequestAsync(address, useDefaultCredentials: true); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(1, response.Headers.WwwAuthenticate.Count); + Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.First().Scheme); + } + } + private async Task SendRequestAsync(string uri, bool useDefaultCredentials = false) { HttpClientHandler handler = new HttpClientHandler(); From c9f0a47c0d688f59ce847c8c8833b34fe48bc675 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 10 Jul 2015 14:50:11 -0700 Subject: [PATCH 225/597] Empty challenge for authenticated request should result in Forbidden. --- .../AuthenticationHandler.cs | 6 ++--- .../AuthenticationTests.cs | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index aa0e411d72..d6f9ebd9ca 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -68,12 +68,12 @@ namespace Microsoft.AspNet.Server.WebListener public Task ChallengeAsync(ChallengeContext context) { + var hasEmptyChallenge = string.IsNullOrEmpty(context.AuthenticationScheme); foreach (var scheme in ListEnabledAuthSchemes()) { var authScheme = scheme.ToString(); // Not including any auth types means it's a blanket challenge for any auth type. - if (string.IsNullOrEmpty(context.AuthenticationScheme) || - string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) + if (hasEmptyChallenge || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) { switch (context.Behavior) { @@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener case ChallengeBehavior.Automatic: var identity = (ClaimsIdentity)_requestContext.User?.Identity; if (identity != null && identity.IsAuthenticated - && string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal)) + && (hasEmptyChallenge || string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal))) { _requestContext.Response.StatusCode = 403; context.Accept(); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 56478fc87f..e6a74f196d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -460,6 +460,30 @@ namespace Microsoft.AspNet.Server.WebListener } } + [Theory] + [InlineData(AuthenticationSchemes.Kerberos)] + [InlineData(AuthenticationSchemes.Negotiate)] + [InlineData(AuthenticationSchemes.NTLM)] + // [InlineData(AuthenticationSchemes.Digest)] // Not implemented + // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials + public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType) + { + string address; + using (Utilities.CreateHttpAuthServer(authType, out address, env => + { + var context = new DefaultHttpContext((IFeatureCollection)env); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + return context.Authentication.ChallengeAsync(); + })) + { + var response = await SendRequestAsync(address, useDefaultCredentials: true); + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + // for some reason Kerberos and Negotiate include a 2nd stage challenge. + // Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + } + } + [Theory] [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] From 1817a1d5b8c04495f24e5f11ba696061ae6ac4bd Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 16 Jul 2015 09:01:20 -0700 Subject: [PATCH 226/597] Updating to release NuGet.config --- NuGet.Config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index da57d47267..0e74a4912d 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,8 @@  - + + - \ No newline at end of file + From 9fdeb09270bb5397be6ab9989fd9d2bd73dbadca Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 17 Jul 2015 09:47:17 -0700 Subject: [PATCH 227/597] React to FeatureModel package change. --- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 1 - src/Microsoft.AspNet.Server.WebListener/MessagePump.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 2 +- .../AuthenticationTests.cs | 2 +- .../HttpsTests.cs | 1 - .../OpaqueUpgradeTests.cs | 1 - .../RequestBodyTests.cs | 2 +- .../RequestHeaderTests.cs | 2 +- .../RequestTests.cs | 1 - .../ResponseBodyTests.cs | 2 +- .../ResponseCachingTests.cs | 2 +- .../ResponseHeaderTests.cs | 1 - .../ResponseSendFileTests.cs | 1 - .../ResponseTests.cs | 1 - .../ServerTests.cs | 2 +- .../WebSocketTests.cs | 1 - 16 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index c4285957cf..dc47ee71d6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -24,7 +24,6 @@ using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; using Microsoft.Net.Http.Headers; diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index 9400c3fe48..038f54176c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -19,7 +19,7 @@ using System; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Features; using Microsoft.Framework.Logging; using Microsoft.Net.Http.Server; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 1c4e9f6497..9c65bc147a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -37,8 +37,8 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Http.Features; using Microsoft.Framework.Configuration; using Microsoft.Framework.Logging; using Microsoft.Net.Http.Server; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index e6a74f196d..68fd03f1cb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -20,7 +20,7 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index f7e1d5a3fa..4078d411b5 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -21,7 +21,6 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 6d5057bba3..0ed71d2efb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -22,7 +22,6 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 1684a888bc..c5edcdf539 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -23,7 +23,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index 01a9e12b98..fcf661891f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -20,7 +20,7 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 72bd8ead4d..898552b1be 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -20,7 +20,6 @@ using System.IO; using System.Net.Http; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Microsoft.Net.Http.Server; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 6c0ae01f85..af31ca78b1 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -23,7 +23,7 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index 3e44988bc6..6378a7e4f8 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -4,7 +4,7 @@ using System; using System.Linq; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index cbf7e8ca3f..27726324c7 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -22,7 +22,6 @@ using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 4814537415..63841ac0b4 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -24,7 +24,6 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index 9767fe11bf..f3381a89c8 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -19,7 +19,6 @@ using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index f35353c52b..edaa0d7736 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -24,8 +24,8 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Microsoft.Net.Http.Server; using Xunit; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index 6fbcc31eb4..c13b6e56ff 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -20,7 +20,6 @@ using System.Net.Http; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; From 2b5206ac1846d09ea4406a5e8633dc27b65e62ee Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 28 Jul 2015 15:01:08 -0700 Subject: [PATCH 228/597] #134 Remove unused fixed buffer. --- .../RequestProcessing/RequestStream.cs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 1ef325a151..3678b298e4 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -248,20 +248,17 @@ namespace Microsoft.Net.Http.Server try { - fixed (byte* pBuffer = buffer) - { - uint flags = 0; + uint flags = 0; - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, - flags, - asyncResult.PinnedBuffer, - (uint)size, - out bytesReturned, - asyncResult.NativeOverlapped); - } + statusCode = + UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( + _requestContext.RequestQueueHandle, + _requestContext.RequestId, + flags, + asyncResult.PinnedBuffer, + (uint)size, + out bytesReturned, + asyncResult.NativeOverlapped); } catch (Exception e) { From aa34e5e46e69dbb9850131ce85bf5f091bd064a0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 29 Jul 2015 15:29:43 -0700 Subject: [PATCH 229/597] React to IFeatureCollection changes. Use a static feature collection. --- .../FeatureContext.cs | 45 +++----- .../StandardFeatureCollection.cs | 105 ++++++++++++++++++ 2 files changed, 122 insertions(+), 28 deletions(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index dc47ee71d6..2ba8740c6f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Server.WebListener private static Func OnStartDelegate = OnStart; private RequestContext _requestContext; - private FeatureCollection _features; + private IFeatureCollection _features; private bool _enableResponseCaching; private Stream _requestBody; @@ -76,11 +76,10 @@ namespace Microsoft.AspNet.Server.WebListener internal FeatureContext(RequestContext requestContext, bool enableResponseCaching) { _requestContext = requestContext; - _features = new FeatureCollection(); + _features = new StandardFeatureCollection(this); _authHandler = new AuthenticationHandler(requestContext); _enableResponseCaching = enableResponseCaching; requestContext.Response.OnStarting(OnStartDelegate, this); - PopulateFeatures(); } internal IFeatureCollection Features @@ -88,6 +87,11 @@ namespace Microsoft.AspNet.Server.WebListener get { return _features; } } + internal object RequestContext + { + get { return _requestContext; } + } + private Request Request { get { return _requestContext.Request; } @@ -98,31 +102,6 @@ namespace Microsoft.AspNet.Server.WebListener get { return _requestContext.Response; } } - private void PopulateFeatures() - { - _features.Add(typeof(IHttpRequestFeature), this); - _features.Add(typeof(IHttpConnectionFeature), this); - _features.Add(typeof(IHttpResponseFeature), this); - _features.Add(typeof(IHttpSendFileFeature), this); - _features.Add(typeof(IHttpBufferingFeature), this); - _features.Add(typeof(IHttpRequestLifetimeFeature), this); - _features.Add(typeof(IHttpAuthenticationFeature), this); - _features.Add(typeof(IHttpRequestIdentifierFeature), this); - - if (Request.IsSecureConnection) - { - _features.Add(typeof(ITlsConnectionFeature), this); - _features.Add(typeof(ITlsTokenBindingFeature), this); - } - - // Win8+ - if (WebSocketHelpers.AreWebSocketsSupported) - { - _features.Add(typeof(IHttpUpgradeFeature), this); - _features.Add(typeof(IHttpWebSocketFeature), this); - } - } - Stream IHttpRequestFeature.Body { get @@ -326,6 +305,11 @@ namespace Microsoft.AspNet.Server.WebListener return _clientCert; } + internal ITlsConnectionFeature GetTlsConnectionFeature() + { + return Request.IsSecureConnection ? this : null; + } + byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId() { return Request.GetProvidedTokenBindingId(); @@ -336,6 +320,11 @@ namespace Microsoft.AspNet.Server.WebListener return Request.GetReferredTokenBindingId(); } + internal ITlsTokenBindingFeature GetTlsTokenBindingFeature() + { + return Request.IsSecureConnection ? this : null; + } + void IHttpBufferingFeature.DisableRequestBuffering() { // There is no request buffering. diff --git a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs new file mode 100644 index 0000000000..a8b735accb --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs @@ -0,0 +1,105 @@ +// Copyright (c) .NET Foundation. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Collections; +using System.Collections.Generic; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.Net.Http.Server; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal sealed class StandardFeatureCollection : IFeatureCollection + { + private static readonly Func _identityFunc = ReturnIdentity; + private static readonly Dictionary> _featureFuncLookup = new Dictionary>() + { + { typeof(IHttpRequestFeature), _identityFunc }, + { typeof(IHttpConnectionFeature), _identityFunc }, + { typeof(IHttpResponseFeature), _identityFunc }, + { typeof(IHttpSendFileFeature), _identityFunc }, + { typeof(ITlsConnectionFeature), ctx => ctx.GetTlsConnectionFeature() }, + { typeof(ITlsTokenBindingFeature), ctx => ctx.GetTlsTokenBindingFeature() }, + { typeof(IHttpBufferingFeature), _identityFunc }, + { typeof(IHttpRequestLifetimeFeature), _identityFunc }, + { typeof(IHttpUpgradeFeature), _identityFunc }, + { typeof(IHttpWebSocketFeature), _identityFunc }, + { typeof(IHttpAuthenticationFeature), _identityFunc }, + { typeof(IHttpRequestIdentifierFeature), _identityFunc }, + { typeof(RequestContext), ctx => ctx.RequestContext }, + }; + + private readonly FeatureContext _featureContext; + + public StandardFeatureCollection(FeatureContext featureContext) + { + _featureContext = featureContext; + } + + public bool IsReadOnly + { + get { return true; } + } + + public int Revision + { + get { return 0; } + } + + public object this[Type key] + { + get + { + Func lookupFunc; + _featureFuncLookup.TryGetValue(key, out lookupFunc); + return lookupFunc?.Invoke(_featureContext); + } + set + { + throw new InvalidOperationException("The collection is read-only"); + } + } + + private static object ReturnIdentity(FeatureContext featureContext) + { + return featureContext; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable>)this).GetEnumerator(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + foreach (var featureFunc in _featureFuncLookup) + { + var feature = featureFunc.Value(_featureContext); + if (feature != null) + { + yield return new KeyValuePair(featureFunc.Key, feature); + } + } + } + + void IDisposable.Dispose() + { + // nothing to dispose of + } + } +} From a24fd18dc0516448f4e9c2003a666d3b112439e4 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 4 Aug 2015 10:15:37 -0700 Subject: [PATCH 230/597] Update CoreCLR versions --- samples/HelloWorld/project.json | 10 ++++---- .../project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 10 ++++---- src/Microsoft.Net.WebSockets/project.json | 24 +++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 940c50ed47..d2cd1453c9 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -9,12 +9,12 @@ "dnx451": { }, "dnxcore50": { "dependencies": { - "System.Collections": "4.0.10-beta-*", + "System.Collections": "4.0.11-beta-*", "System.Console": "4.0.0-beta-*", - "System.Globalization": "4.0.10-beta-*", - "System.IO": "4.0.10-beta-*", - "System.Runtime": "4.0.20-beta-*", - "System.Threading.Tasks": "4.0.10-beta-*" + "System.Globalization": "4.0.11-beta-*", + "System.IO": "4.0.11-beta-*", + "System.Runtime": "4.0.21-beta-*", + "System.Threading.Tasks": "4.0.11-beta-*" } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index d2f2494450..323f1f29e6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -13,7 +13,7 @@ "dnx451": { }, "dnxcore50": { "dependencies": { - "System.Security.Claims": "4.0.0-beta-*" + "System.Security.Claims": "4.0.1-beta-*" } } } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 4859950613..8356811d61 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -13,13 +13,13 @@ "dnx451": { }, "dnxcore50": { "dependencies": { - "Microsoft.Win32.Primitives": "4.0.0-beta-*", - "System.Diagnostics.Debug": "4.0.10-beta-*", - "System.IO.FileSystem": "4.0.0-beta-*", - "System.Security.Claims": "4.0.0-beta-*", + "Microsoft.Win32.Primitives": "4.0.1-beta-*", + "System.Diagnostics.Debug": "4.0.11-beta-*", + "System.IO.FileSystem": "4.0.1-beta-*", + "System.Security.Claims": "4.0.1-beta-*", "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", "System.Security.Principal.Windows": "4.0.0-beta-*", - "System.Threading.Overlapped": "4.0.0-beta-*" + "System.Threading.Overlapped": "4.0.1-beta-*" } } } diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 50fa32a2e1..e2fc8bb602 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -9,20 +9,20 @@ "dnx451": { }, "dnxcore50": { "dependencies": { - "System.Collections": "4.0.10-beta-*", - "System.Diagnostics.Contracts": "4.0.0-beta-*", - "System.Diagnostics.Tools": "4.0.0-beta-*", - "System.IO": "4.0.10-beta-*", - "System.Linq": "4.0.0-beta-*", - "System.Net.Primitives": "4.0.10-beta-*", + "System.Collections": "4.0.11-beta-*", + "System.Diagnostics.Contracts": "4.0.1-beta-*", + "System.Diagnostics.Tools": "4.0.1-beta-*", + "System.IO": "4.0.11-beta-*", + "System.Linq": "4.0.1-beta-*", + "System.Net.Primitives": "4.0.11-beta-*", "System.Net.WebSockets": "4.0.0-beta-*", - "System.Resources.ResourceManager": "4.0.0-beta-*", - "System.Runtime.Extensions": "4.0.10-beta-*", + "System.Resources.ResourceManager": "4.0.1-beta-*", + "System.Runtime.Extensions": "4.0.11-beta-*", "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", - "System.Text.Encoding.Extensions": "4.0.10-beta-*", - "System.Threading": "4.0.10-beta-*", - "System.Threading.Tasks": "4.0.10-beta-*", - "System.Threading.Timer": "4.0.0-beta-*", + "System.Text.Encoding.Extensions": "4.0.11-beta-*", + "System.Threading": "4.0.11-beta-*", + "System.Threading.Tasks": "4.0.11-beta-*", + "System.Threading.Timer": "4.0.1-beta-*", "System.Threading.ThreadPool": "4.0.10-beta-*" } } From 28d3b1868638868acf5b730e0c2cb52268758581 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 7 Aug 2015 16:01:36 -0700 Subject: [PATCH 231/597] #43 Honor CancellationTokens in GetClientCertificateAsync. --- .../RequestProcessing/ClientCertLoader.cs | 15 +++++++++++---- .../RequestProcessing/Request.cs | 5 +++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs index e859c97964..8ae8305a87 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs @@ -50,14 +50,20 @@ namespace Microsoft.Net.Http.Server private int _clientCertError; private X509Certificate2 _clientCert; private Exception _clientCertException; + private CancellationTokenRegistration _cancellationRegistration; - internal ClientCertLoader(RequestContext requestContext) + internal ClientCertLoader(RequestContext requestContext, CancellationToken cancellationToken) { _requestContext = requestContext; _tcs = new TaskCompletionSource(); // we will use this overlapped structure to issue async IO to ul // the event handle will be put in by the BeginHttpApi2.ERROR_SUCCESS() method Reset(CertBoblSize); + + if (cancellationToken.CanBeCanceled) + { + _cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + } } internal X509Certificate2 ClientCert @@ -162,9 +168,8 @@ namespace Microsoft.Net.Http.Server // ERROR_NOT_FOUND - which means the client did not provide the cert // If this is important, the server should respond with 403 forbidden // HTTP.SYS will not do this for you automatically - internal Task LoadClientCertificateAsync(CancellationToken cancellationToken) + internal Task LoadClientCertificateAsync() { - // TODO: cancellation support? Abort the request? uint size = CertBoblSize; bool retry; do @@ -218,14 +223,15 @@ namespace Microsoft.Net.Http.Server // May be null _clientCert = cert; _clientCertError = certErrors; - _tcs.TrySetResult(null); Dispose(); + _tcs.TrySetResult(null); } private void Fail(Exception ex) { // TODO: Log _clientCertException = ex; + Dispose(); _tcs.TrySetResult(null); } @@ -328,6 +334,7 @@ namespace Microsoft.Net.Http.Server { if (disposing) { + _cancellationRegistration.Dispose(); if (_overlapped != null) { _memoryBlob = null; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 51333996fc..146f0cf81e 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -451,11 +451,12 @@ namespace Microsoft.Net.Http.Server { return _clientCert; } + cancellationToken.ThrowIfCancellationRequested(); - ClientCertLoader certLoader = new ClientCertLoader(RequestContext); + ClientCertLoader certLoader = new ClientCertLoader(RequestContext, cancellationToken); try { - await certLoader.LoadClientCertificateAsync(cancellationToken).SupressContext(); + await certLoader.LoadClientCertificateAsync().SupressContext(); // Populate the environment. if (certLoader.ClientCert != null) { From 311127e8410ea0a2de086796ba4c482b85732bb3 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 11 Aug 2015 14:38:16 -0700 Subject: [PATCH 232/597] #139 React to CoreCLR Crytopgraphy package changes. --- src/Microsoft.Net.WebSockets/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index e2fc8bb602..23db5571cb 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -18,7 +18,7 @@ "System.Net.WebSockets": "4.0.0-beta-*", "System.Resources.ResourceManager": "4.0.1-beta-*", "System.Runtime.Extensions": "4.0.11-beta-*", - "System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*", + "System.Security.Cryptography.Algorithms": "4.0.0-beta-*", "System.Text.Encoding.Extensions": "4.0.11-beta-*", "System.Threading": "4.0.11-beta-*", "System.Threading.Tasks": "4.0.11-beta-*", From ae173cb875452cb101db72db33fb85a9eccc868c Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Wed, 12 Aug 2015 05:35:20 -0700 Subject: [PATCH 233/597] Enable pinning build script --- build.cmd | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/build.cmd b/build.cmd index 41025afb26..ccf195aee8 100644 --- a/build.cmd +++ b/build.cmd @@ -3,6 +3,8 @@ cd %~dp0 SETLOCAL SET CACHED_NUGET=%LocalAppData%\NuGet\NuGet.exe +SET BUILDCMD_KOREBUILD_VERSION="" +SET BUILDCMD_DNX_VERSION="" IF EXIST %CACHED_NUGET% goto copynuget echo Downloading latest version of NuGet.exe... @@ -16,13 +18,21 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore IF EXIST packages\KoreBuild goto run -.nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre +IF %BUILDCMD_KOREBUILD_VERSION%=="" ( + .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre +) ELSE ( + .nuget\NuGet.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre +) .nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion IF "%SKIP_DNX_INSTALL%"=="1" goto run -CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +IF %BUILDCMD_DNX_VERSION%=="" ( + CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +) ELSE ( + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -a default +) CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 :run CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* \ No newline at end of file From 87e1acf034bb5b44e462ffb848487357e3f6ac73 Mon Sep 17 00:00:00 2001 From: Kirthi Krishnamraju Date: Thu, 13 Aug 2015 22:59:09 -0700 Subject: [PATCH 234/597] fix build break due to aspnet/Configuration #246 --- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 9c65bc147a..693106a9c9 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -102,9 +102,9 @@ namespace Microsoft.AspNet.Server.WebListener private void ParseAddresses(IConfiguration config, Microsoft.Net.Http.Server.WebListener listener) { // TODO: Key format? - string urls; - if (config != null && config.TryGet("server.urls", out urls) && !string.IsNullOrEmpty(urls)) + if (config != null && !string.IsNullOrEmpty(config["server.urls"])) { + var urls = config["server.urls"]; foreach (var value in urls.Split(';')) { listener.UrlPrefixes.Add(UrlPrefix.Create(value)); From 8735d455f9b42b7c6bf095c795aad5cfa6804786 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 17 Aug 2015 09:46:49 -0700 Subject: [PATCH 235/597] Only run Kerberos tests if the machine is joined to the domain. --- .../AuthenticationTests.cs | 47 +++++---------- .../AuthenticationTests.cs | 59 +++++++++++++++---- .../SkipOffDomainAttribute.cs | 39 ++++++++++++ .../project.json | 31 +++++----- 4 files changed, 117 insertions(+), 59 deletions(-) create mode 100644 test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 68fd03f1cb..d8a2fa3e66 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -32,12 +32,11 @@ namespace Microsoft.AspNet.Server.WebListener { [Theory] [InlineData(AuthenticationSchemes.AllowAnonymous)] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) { string address; @@ -56,7 +55,6 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -76,7 +74,6 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -104,8 +101,7 @@ namespace Microsoft.AspNet.Server.WebListener { string address; using (Utilities.CreateHttpAuthServer( - AuthenticationSchemes.Kerberos - | AuthenticationSchemes.Negotiate + AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM /* | AuthenticationSchemes.Digest TODO: Not implemented */ | AuthenticationSchemes.Basic @@ -122,17 +118,16 @@ namespace Microsoft.AspNet.Server.WebListener { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); - Assert.Equal("Kerberos, Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + Assert.Equal("Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType) { string address; @@ -164,12 +159,11 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) { string address; @@ -188,12 +182,10 @@ namespace Microsoft.AspNet.Server.WebListener [Theory] [InlineData(AuthenticationSchemes.AllowAnonymous)] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] - // [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_GetSingleDescriptions(AuthenticationSchemes authType) { string address; @@ -227,8 +219,7 @@ namespace Microsoft.AspNet.Server.WebListener { string address; AuthenticationSchemes authType = - AuthenticationSchemes.Kerberos - | AuthenticationSchemes.Negotiate + AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; @@ -236,7 +227,7 @@ namespace Microsoft.AspNet.Server.WebListener { var context = new DefaultHttpContext((IFeatureCollection)env); var resultList = context.Authentication.GetAuthenticationSchemes(); - Assert.Equal(4, resultList.Count()); + Assert.Equal(3, resultList.Count()); return Task.FromResult(0); })) { @@ -247,12 +238,11 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationSchemes authType) { string address; @@ -276,12 +266,11 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationSchemes authType) { string address; @@ -309,12 +298,11 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { string address; @@ -334,12 +322,11 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { string address; @@ -362,7 +349,6 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -370,7 +356,7 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationSchemes authType) { string address; - var authTypes = AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; + var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); @@ -387,7 +373,6 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -395,7 +380,7 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_ChallengeDisabledAuthType_Error(AuthenticationSchemes authType) { string address; - var authTypes = AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; + var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; authTypes = authTypes & ~authType; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, env => @@ -413,7 +398,6 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -421,7 +405,7 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_Forbid_Forbidden(AuthenticationSchemes authType) { string address; - var authTypes = AuthenticationSchemes.AllowAnonymous | AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; + var authTypes = AuthenticationSchemes.AllowAnonymous | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; using (Utilities.CreateHttpAuthServer(authTypes, out address, env => { var context = new DefaultHttpContext((IFeatureCollection)env); @@ -437,7 +421,6 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented @@ -461,7 +444,6 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented @@ -485,7 +467,6 @@ namespace Microsoft.AspNet.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index f9e9316dc8..7c4272cd51 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -4,6 +4,7 @@ using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server @@ -12,12 +13,11 @@ namespace Microsoft.Net.Http.Server { [Theory] [InlineData(AuthenticationSchemes.AllowAnonymous)] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) { string address; @@ -45,7 +45,6 @@ namespace Microsoft.Net.Http.Server } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented @@ -66,7 +65,6 @@ namespace Microsoft.Net.Http.Server } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -96,8 +94,7 @@ namespace Microsoft.Net.Http.Server { string address; AuthenticationSchemes authType = - AuthenticationSchemes.Kerberos - | AuthenticationSchemes.Negotiate + AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM /* | AuthenticationSchemes.Digest TODO: Not implemented */ | AuthenticationSchemes.Basic; @@ -114,17 +111,16 @@ namespace Microsoft.Net.Http.Server var response = await responseTask; Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); - Assert.Equal("Kerberos, Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + Assert.Equal("Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType) { string address; @@ -151,12 +147,11 @@ namespace Microsoft.Net.Http.Server } [Theory] - [InlineData(AuthenticationSchemes.Kerberos)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented // [InlineData(AuthenticationSchemes.Basic)] // Doesn't work with default creds - [InlineData(AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) { string address; @@ -175,6 +170,48 @@ namespace Microsoft.Net.Http.Server } } + [ConditionalTheory] + [SkipOffDomain] + public async Task AuthTypes_RequireKerberosAuth_Success() + { + string address; + using (var server = Utilities.CreateHttpAuthServer(AuthenticationSchemes.Kerberos, out address)) + { + Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); + + var context = await server.GetContextAsync(); + Assert.NotNull(context.User); + Assert.True(context.User.Identity.IsAuthenticated); + Assert.Equal(AuthenticationSchemes.Kerberos, context.AuthenticationChallenges); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + } + + [ConditionalTheory] + [SkipOffDomain] + public async Task MultipleAuthTypes_KerberosAllowAnonymousButSpecify401_ChallengesAdded() + { + string address; + using (var server = Utilities.CreateHttpAuthServer(AuthenticationSchemes.Kerberos | AuthenticationSchemes.AllowAnonymous, out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + Assert.NotNull(context.User); + Assert.False(context.User.Identity.IsAuthenticated); + Assert.Equal(AuthenticationSchemes.Kerberos, context.AuthenticationChallenges); + context.Response.StatusCode = 401; + context.Dispose(); + + var response = await responseTask; + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal("Kerberos", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); + } + } + private async Task SendRequestAsync(string uri, bool useDefaultCredentials = false) { HttpClientHandler handler = new HttpClientHandler(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs new file mode 100644 index 0000000000..11a7bb82fb --- /dev/null +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs @@ -0,0 +1,39 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.DirectoryServices.ActiveDirectory; +using Microsoft.AspNet.Testing.xunit; + +namespace Microsoft.Net.Http.Server +{ + /// + /// Skips an auth test if the machine is not joined to a Windows domain. + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class SkipOffDomainAttribute : Attribute, ITestCondition + { + public bool IsMet + { + get + { + try + { + return !string.IsNullOrEmpty(Domain.GetComputerDomain().Name); + } + catch + { + } + return false; + } + } + + public string SkipReason + { + get + { + return "Machine is not joined to a domain."; + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index d5a72c4598..586047d801 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,18 +1,19 @@ { - "commands": { - "test": "xunit.runner.aspnet" - }, - "dependencies": { - "Microsoft.Net.Http.Server": "1.0.0-*", - "Microsoft.AspNet.Testing": "1.0.0-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "frameworks": { - "dnx451": { - "frameworkAssemblies": { - "System.Net.Http": "", - "System.Net.Http.WebRequest": "" - } - } + "commands": { + "test": "xunit.runner.aspnet" + }, + "dependencies": { + "Microsoft.Net.Http.Server": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "frameworks": { + "dnx451": { + "frameworkAssemblies": { + "System.DirectoryServices": "", + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" + } } + } } From 113a86d6a326c2ddc218cdf667b0666a7776f422 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 17 Aug 2015 14:48:39 -0700 Subject: [PATCH 236/597] Updating to release NuGet.config. --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index da57d47267..3b8d545754 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file From 5d0ae6f7224482bfefdba783f135d6d4e92564af Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 18 Aug 2015 14:00:22 -0700 Subject: [PATCH 237/597] Updating to aspnetliterelease. --- NuGet.Config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.Config b/NuGet.Config index 3b8d545754..e2378fe359 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@ - + \ No newline at end of file From 59db2da45dca8c8af378cdae0be0823239089dd3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 18 Aug 2015 14:00:22 -0700 Subject: [PATCH 238/597] Updating to aspnetlitedev. --- NuGet.Config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index da57d47267..6685c5330a 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file From 5ed1ef9d6286c40b52d70b9c08f0f7eb552e98b8 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 19 Aug 2015 14:54:10 -0700 Subject: [PATCH 239/597] Update NuGet feed from v2 => v3. --- NuGet.Config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.Config b/NuGet.Config index 6685c5330a..10cec18a32 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -2,6 +2,6 @@ - + \ No newline at end of file From 18d478d5cfe3da2591cd349b7bbf1f7125c8755c Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 20 Aug 2015 15:37:51 -0700 Subject: [PATCH 240/597] Update 'build.cmd' to pull Sake from v2 NuGet feed. --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index ccf195aee8..b54d91cf74 100644 --- a/build.cmd +++ b/build.cmd @@ -23,7 +23,7 @@ IF %BUILDCMD_KOREBUILD_VERSION%=="" ( ) ELSE ( .nuget\NuGet.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre ) -.nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion +.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages IF "%SKIP_DNX_INSTALL%"=="1" goto run IF %BUILDCMD_DNX_VERSION%=="" ( From b4ea8a59ff7a1d7afffb05152ca85733e10a3acf Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 20 Aug 2015 20:46:43 -0700 Subject: [PATCH 241/597] Update 'build.sh' to pull Sake from v2 NuGet feed. --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 3ef874f9bd..68c3e8cb52 100755 --- a/build.sh +++ b/build.sh @@ -24,7 +24,7 @@ fi if test ! -d packages/KoreBuild; then mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -version 0.2 -o packages -ExcludeVersion + mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages fi if ! type dnvm > /dev/null 2>&1; then From 42343bedeed6dfefa837dc2cdc42aab303c2c848 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 24 Aug 2015 10:52:50 -0700 Subject: [PATCH 242/597] Raise test timeouts. --- .../ServerTests.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index edaa0d7736..e3299693f5 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -150,12 +150,7 @@ namespace Microsoft.AspNet.Server.WebListener requestTasks.Add(requestTask); } - bool success = Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(10)); - if (!success) - { - Console.WriteLine(); - } - Assert.True(success, "Timed out"); + Assert.True(Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(60)), "Timed out"); } } @@ -185,7 +180,7 @@ namespace Microsoft.AspNet.Server.WebListener Task requestTask = SendRequestAsync(address); requestTasks.Add(requestTask); } - Assert.True(Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(2)), "Timed out"); + Assert.True(Task.WaitAll(requestTasks.ToArray(), TimeSpan.FromSeconds(60)), "Timed out"); } } From 1f596abfe56c49d89e83d124040cc098b0cb8613 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 28 Aug 2015 12:43:12 -0700 Subject: [PATCH 243/597] React to string[] -> StringValues changes. --- .../FeatureContext.cs | 9 +- .../AuthenticationManager.cs | 4 +- .../NativeInterop/UnsafeNativeMethods.cs | 5 +- .../RequestProcessing/HeaderCollection.cs | 95 ++-- .../RequestProcessing/HeaderParser.cs | 3 +- .../RequestProcessing/Request.cs | 10 +- .../RequestProcessing/RequestContext.cs | 14 +- .../RequestHeaders.Generated.cs | 423 +++++++++--------- .../RequestHeaders.Generated.tt | 19 +- .../RequestProcessing/RequestHeaders.cs | 41 +- .../RequestProcessing/Response.cs | 37 +- src/Microsoft.Net.Http.Server/project.json | 1 + .../RequestHeaderTests.cs | 17 +- .../RequestHeaderTests.cs | 5 +- .../ResponseHeaderTests.cs | 12 +- 15 files changed, 331 insertions(+), 364 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 2ba8740c6f..f40812631f 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -26,6 +26,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.Framework.Primitives; using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Server; using Microsoft.Net.WebSockets; @@ -53,7 +54,7 @@ namespace Microsoft.AspNet.Server.WebListener private bool _enableResponseCaching; private Stream _requestBody; - private IDictionary _requestHeaders; + private IDictionary _requestHeaders; private string _scheme; private string _httpMethod; private string _httpProtocolVersion; @@ -71,7 +72,7 @@ namespace Microsoft.AspNet.Server.WebListener private IAuthenticationHandler _authHandler; private CancellationToken? _disconnectToken; private Stream _responseStream; - private IDictionary _responseHeaders; + private IDictionary _responseHeaders; internal FeatureContext(RequestContext requestContext, bool enableResponseCaching) { @@ -115,7 +116,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _requestBody = value; } } - IDictionary IHttpRequestFeature.Headers + IDictionary IHttpRequestFeature.Headers { get { @@ -348,7 +349,7 @@ namespace Microsoft.AspNet.Server.WebListener set { _responseStream = value; } } - IDictionary IHttpResponseFeature.Headers + IDictionary IHttpResponseFeature.Headers { get { diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 76377dd63c..321851995f 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -27,6 +27,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Principal; +using Microsoft.Framework.Primitives; namespace Microsoft.Net.Http.Server { @@ -147,7 +148,8 @@ namespace Microsoft.Net.Http.Server if (challenges.Count > 0) { - context.Response.Headers.AppendValues(HttpKnownHeaderNames.WWWAuthenticate, challenges.ToArray()); + context.Response.Headers[HttpKnownHeaderNames.WWWAuthenticate] + = StringValues.Concat(context.Response.Headers[HttpKnownHeaderNames.WWWAuthenticate], challenges.ToArray()); } } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index 2b2c05b6a3..c4464119a8 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using Microsoft.Framework.Primitives; namespace Microsoft.Net.Http.Server { @@ -1048,7 +1049,7 @@ namespace Microsoft.Net.Http.Server // Server API - internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob, IntPtr originalAddress) + internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob, IntPtr originalAddress) { // Return value. fixed (byte* pMemoryBlob = memoryBlob) @@ -1079,7 +1080,7 @@ namespace Microsoft.Net.Http.Server } // Note that Http.Sys currently collapses all headers of the same name to a single coma seperated string, // so we can just call Set. - unknownHeaders[headerName] = new[] { headerValue }; + unknownHeaders[headerName] = headerValue; } pUnknownHeader++; } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs index 87ee134733..2190b3dd2f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs @@ -4,44 +4,49 @@ using System; using System.Collections; using System.Collections.Generic; +using Microsoft.Framework.Primitives; namespace Microsoft.Net.Http.Server { - public class HeaderCollection : IDictionary + public class HeaderCollection : IDictionary { public HeaderCollection() - : this(new Dictionary(4, StringComparer.OrdinalIgnoreCase)) + : this(new Dictionary(4, StringComparer.OrdinalIgnoreCase)) { } - public HeaderCollection(IDictionary store) + public HeaderCollection(IDictionary store) { Store = store; } - private IDictionary Store { get; set; } + private IDictionary Store { get; set; } // Readonly after the response has been started. public bool IsReadOnly { get; internal set; } - public string this[string key] + public StringValues this[string key] { - get { return Get(key); } + get + { + StringValues values; + return TryGetValue(key, out values) ? values : StringValues.Empty; + } set { ThrowIfReadOnly(); - if (string.IsNullOrEmpty(value)) + if (StringValues.IsNullOrEmpty(value)) { Remove(key); } else { - Set(key, value); + Store[key] = value; } } } - string[] IDictionary.this[string key] + StringValues IDictionary.this[string key] { get { return Store[key]; } set @@ -61,18 +66,18 @@ namespace Microsoft.Net.Http.Server get { return Store.Keys; } } - public ICollection Values + public ICollection Values { get { return Store.Values; } } - public void Add(KeyValuePair item) + public void Add(KeyValuePair item) { ThrowIfReadOnly(); Store.Add(item); } - public void Add(string key, string[] value) + public void Add(string key, StringValues value) { ThrowIfReadOnly(); Store.Add(key, value); @@ -81,35 +86,9 @@ namespace Microsoft.Net.Http.Server public void Append(string key, string value) { ThrowIfReadOnly(); - string[] values; - if (Store.TryGetValue(key, out values)) - { - var newValues = new string[values.Length + 1]; - Array.Copy(values, newValues, values.Length); - newValues[values.Length] = value; - Store[key] = newValues; - } - else - { - Set(key, value); - } - } - - public void AppendValues(string key, params string[] values) - { - ThrowIfReadOnly(); - string[] oldValues; - if (Store.TryGetValue(key, out oldValues)) - { - var newValues = new string[oldValues.Length + values.Length]; - Array.Copy(oldValues, newValues, oldValues.Length); - Array.Copy(values, 0, newValues, oldValues.Length, values.Length); - Store[key] = newValues; - } - else - { - SetValues(key, values); - } + StringValues values; + Store.TryGetValue(key, out values); + Store[key] = StringValues.Concat(values, value); } public void Clear() @@ -118,7 +97,7 @@ namespace Microsoft.Net.Http.Server Store.Clear(); } - public bool Contains(KeyValuePair item) + public bool Contains(KeyValuePair item) { return Store.Contains(item); } @@ -128,29 +107,19 @@ namespace Microsoft.Net.Http.Server return Store.ContainsKey(key); } - public void CopyTo(KeyValuePair[] array, int arrayIndex) + public void CopyTo(KeyValuePair[] array, int arrayIndex) { Store.CopyTo(array, arrayIndex); } - public string Get(string key) - { - string[] values; - if (Store.TryGetValue(key, out values)) - { - return string.Join(", ", values); - } - return null; - } - - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { return Store.GetEnumerator(); } public IEnumerable GetValues(string key) { - string[] values; + StringValues values; if (Store.TryGetValue(key, out values)) { return HeaderParser.SplitValues(values); @@ -158,7 +127,7 @@ namespace Microsoft.Net.Http.Server return HeaderParser.Empty; } - public bool Remove(KeyValuePair item) + public bool Remove(KeyValuePair item) { ThrowIfReadOnly(); return Store.Remove(item); @@ -170,19 +139,7 @@ namespace Microsoft.Net.Http.Server return Store.Remove(key); } - public void Set(string key, string value) - { - ThrowIfReadOnly(); - Store[key] = new[] { value }; - } - - public void SetValues(string key, params string[] values) - { - ThrowIfReadOnly(); - Store[key] = values; - } - - public bool TryGetValue(string key, out string[] value) + public bool TryGetValue(string key, out StringValues value) { return Store.TryGetValue(key, out value); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs index ebc77b8203..d4694415d6 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Microsoft.Framework.Primitives; namespace Microsoft.Net.Http.Server { @@ -11,7 +12,7 @@ namespace Microsoft.Net.Http.Server internal static IEnumerable Empty = new string[0]; // Split on commas, except in quotes - internal static IEnumerable SplitValues(string[] values) + internal static IEnumerable SplitValues(StringValues values) { foreach (var value in values) { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 146f0cf81e..2043da2957 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -231,16 +231,16 @@ namespace Microsoft.Net.Http.Server { if (_contentBoundaryType == BoundaryType.None) { - string transferEncoding = Headers.Get(HttpKnownHeaderNames.TransferEncoding) ?? string.Empty; - if (string.Equals("chunked", transferEncoding.Trim(), StringComparison.OrdinalIgnoreCase)) + string transferEncoding = Headers[HttpKnownHeaderNames.TransferEncoding]; + if (string.Equals("chunked", transferEncoding?.Trim(), StringComparison.OrdinalIgnoreCase)) { _contentBoundaryType = BoundaryType.Chunked; } else { - string length = Headers.Get(HttpKnownHeaderNames.ContentLength) ?? string.Empty; + string length = Headers[HttpKnownHeaderNames.ContentLength]; long value; - if (long.TryParse(length.Trim(), NumberStyles.None, + if (length != null && long.TryParse(length.Trim(), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out value)) { _contentBoundaryType = BoundaryType.ContentLength; @@ -422,7 +422,7 @@ namespace Microsoft.Net.Http.Server { get { - return Headers.Get(HttpKnownHeaderNames.ContentType); + return Headers[HttpKnownHeaderNames.ContentType]; } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 757cb4e7de..905fe8db18 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -194,8 +194,8 @@ namespace Microsoft.Net.Http.Server } // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - string connection = Request.Headers[HttpKnownHeaderNames.Connection] ?? string.Empty; - if (connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) + string connection = Request.Headers[HttpKnownHeaderNames.Connection]; + if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) { return false; } @@ -244,8 +244,8 @@ namespace Microsoft.Net.Http.Server } // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - string connection = Request.Headers[HttpKnownHeaderNames.Connection] ?? string.Empty; - if (connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) + string connection = Request.Headers[HttpKnownHeaderNames.Connection]; + if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) { throw new InvalidOperationException("The Connection header is invalid: " + connection); } @@ -345,9 +345,9 @@ namespace Microsoft.Net.Http.Server string secWebSocketKey = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); - Response.Headers.AppendValues(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); - Response.Headers.AppendValues(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); - Response.Headers.AppendValues(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); + Response.Headers.Append(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); + Response.Headers.Append(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); + Response.Headers.Append(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); Stream opaqueStream = await UpgradeAsync(); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs index 66019a500e..1326e7204d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using Microsoft.Framework.Primitives; namespace Microsoft.Net.Http.Server { @@ -36,52 +37,52 @@ namespace Microsoft.Net.Http.Server internal partial class RequestHeaders { // Tracks if individual fields have been read from native or set directly. - // Once read or set, their presence in the collection is marked by if their string[] is null or not. + // Once read or set, their presence in the collection is marked by if their StringValues is null or not. private UInt32 _flag0, _flag1; - private string[] _Accept; - private string[] _AcceptCharset; - private string[] _AcceptEncoding; - private string[] _AcceptLanguage; - private string[] _Allow; - private string[] _Authorization; - private string[] _CacheControl; - private string[] _Connection; - private string[] _ContentEncoding; - private string[] _ContentLanguage; - private string[] _ContentLength; - private string[] _ContentLocation; - private string[] _ContentMd5; - private string[] _ContentRange; - private string[] _ContentType; - private string[] _Cookie; - private string[] _Date; - private string[] _Expect; - private string[] _Expires; - private string[] _From; - private string[] _Host; - private string[] _IfMatch; - private string[] _IfModifiedSince; - private string[] _IfNoneMatch; - private string[] _IfRange; - private string[] _IfUnmodifiedSince; - private string[] _KeepAlive; - private string[] _LastModified; - private string[] _MaxForwards; - private string[] _Pragma; - private string[] _ProxyAuthorization; - private string[] _Range; - private string[] _Referer; - private string[] _Te; - private string[] _Trailer; - private string[] _TransferEncoding; - private string[] _Translate; - private string[] _Upgrade; - private string[] _UserAgent; - private string[] _Via; - private string[] _Warning; + private StringValues _Accept; + private StringValues _AcceptCharset; + private StringValues _AcceptEncoding; + private StringValues _AcceptLanguage; + private StringValues _Allow; + private StringValues _Authorization; + private StringValues _CacheControl; + private StringValues _Connection; + private StringValues _ContentEncoding; + private StringValues _ContentLanguage; + private StringValues _ContentLength; + private StringValues _ContentLocation; + private StringValues _ContentMd5; + private StringValues _ContentRange; + private StringValues _ContentType; + private StringValues _Cookie; + private StringValues _Date; + private StringValues _Expect; + private StringValues _Expires; + private StringValues _From; + private StringValues _Host; + private StringValues _IfMatch; + private StringValues _IfModifiedSince; + private StringValues _IfNoneMatch; + private StringValues _IfRange; + private StringValues _IfUnmodifiedSince; + private StringValues _KeepAlive; + private StringValues _LastModified; + private StringValues _MaxForwards; + private StringValues _Pragma; + private StringValues _ProxyAuthorization; + private StringValues _Range; + private StringValues _Referer; + private StringValues _Te; + private StringValues _Trailer; + private StringValues _TransferEncoding; + private StringValues _Translate; + private StringValues _Upgrade; + private StringValues _UserAgent; + private StringValues _Via; + private StringValues _Warning; - internal string[] Accept + internal StringValues Accept { get { @@ -90,7 +91,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Accept); if (nativeValue != null) { - _Accept = new string[] { nativeValue }; + _Accept = nativeValue; } _flag0 |= 0x1u; } @@ -103,7 +104,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] AcceptCharset + internal StringValues AcceptCharset { get { @@ -112,7 +113,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.AcceptCharset); if (nativeValue != null) { - _AcceptCharset = new string[] { nativeValue }; + _AcceptCharset = nativeValue; } _flag0 |= 0x2u; } @@ -125,7 +126,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] AcceptEncoding + internal StringValues AcceptEncoding { get { @@ -134,7 +135,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.AcceptEncoding); if (nativeValue != null) { - _AcceptEncoding = new string[] { nativeValue }; + _AcceptEncoding = nativeValue; } _flag0 |= 0x4u; } @@ -147,7 +148,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] AcceptLanguage + internal StringValues AcceptLanguage { get { @@ -156,7 +157,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.AcceptLanguage); if (nativeValue != null) { - _AcceptLanguage = new string[] { nativeValue }; + _AcceptLanguage = nativeValue; } _flag0 |= 0x8u; } @@ -169,7 +170,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Allow + internal StringValues Allow { get { @@ -178,7 +179,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Allow); if (nativeValue != null) { - _Allow = new string[] { nativeValue }; + _Allow = nativeValue; } _flag0 |= 0x10u; } @@ -191,7 +192,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Authorization + internal StringValues Authorization { get { @@ -200,7 +201,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Authorization); if (nativeValue != null) { - _Authorization = new string[] { nativeValue }; + _Authorization = nativeValue; } _flag0 |= 0x20u; } @@ -213,7 +214,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] CacheControl + internal StringValues CacheControl { get { @@ -222,7 +223,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.CacheControl); if (nativeValue != null) { - _CacheControl = new string[] { nativeValue }; + _CacheControl = nativeValue; } _flag0 |= 0x40u; } @@ -235,7 +236,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Connection + internal StringValues Connection { get { @@ -244,7 +245,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Connection); if (nativeValue != null) { - _Connection = new string[] { nativeValue }; + _Connection = nativeValue; } _flag0 |= 0x80u; } @@ -257,7 +258,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] ContentEncoding + internal StringValues ContentEncoding { get { @@ -266,7 +267,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentEncoding); if (nativeValue != null) { - _ContentEncoding = new string[] { nativeValue }; + _ContentEncoding = nativeValue; } _flag0 |= 0x100u; } @@ -279,7 +280,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] ContentLanguage + internal StringValues ContentLanguage { get { @@ -288,7 +289,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentLanguage); if (nativeValue != null) { - _ContentLanguage = new string[] { nativeValue }; + _ContentLanguage = nativeValue; } _flag0 |= 0x200u; } @@ -301,7 +302,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] ContentLength + internal StringValues ContentLength { get { @@ -310,7 +311,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentLength); if (nativeValue != null) { - _ContentLength = new string[] { nativeValue }; + _ContentLength = nativeValue; } _flag0 |= 0x400u; } @@ -323,7 +324,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] ContentLocation + internal StringValues ContentLocation { get { @@ -332,7 +333,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentLocation); if (nativeValue != null) { - _ContentLocation = new string[] { nativeValue }; + _ContentLocation = nativeValue; } _flag0 |= 0x800u; } @@ -345,7 +346,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] ContentMd5 + internal StringValues ContentMd5 { get { @@ -354,7 +355,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentMd5); if (nativeValue != null) { - _ContentMd5 = new string[] { nativeValue }; + _ContentMd5 = nativeValue; } _flag0 |= 0x1000u; } @@ -367,7 +368,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] ContentRange + internal StringValues ContentRange { get { @@ -376,7 +377,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentRange); if (nativeValue != null) { - _ContentRange = new string[] { nativeValue }; + _ContentRange = nativeValue; } _flag0 |= 0x2000u; } @@ -389,7 +390,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] ContentType + internal StringValues ContentType { get { @@ -398,7 +399,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.ContentType); if (nativeValue != null) { - _ContentType = new string[] { nativeValue }; + _ContentType = nativeValue; } _flag0 |= 0x4000u; } @@ -411,7 +412,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Cookie + internal StringValues Cookie { get { @@ -420,7 +421,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Cookie); if (nativeValue != null) { - _Cookie = new string[] { nativeValue }; + _Cookie = nativeValue; } _flag0 |= 0x8000u; } @@ -433,7 +434,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Date + internal StringValues Date { get { @@ -442,7 +443,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Date); if (nativeValue != null) { - _Date = new string[] { nativeValue }; + _Date = nativeValue; } _flag0 |= 0x10000u; } @@ -455,7 +456,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Expect + internal StringValues Expect { get { @@ -464,7 +465,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Expect); if (nativeValue != null) { - _Expect = new string[] { nativeValue }; + _Expect = nativeValue; } _flag0 |= 0x20000u; } @@ -477,7 +478,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Expires + internal StringValues Expires { get { @@ -486,7 +487,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Expires); if (nativeValue != null) { - _Expires = new string[] { nativeValue }; + _Expires = nativeValue; } _flag0 |= 0x40000u; } @@ -499,7 +500,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] From + internal StringValues From { get { @@ -508,7 +509,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.From); if (nativeValue != null) { - _From = new string[] { nativeValue }; + _From = nativeValue; } _flag0 |= 0x80000u; } @@ -521,7 +522,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Host + internal StringValues Host { get { @@ -530,7 +531,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Host); if (nativeValue != null) { - _Host = new string[] { nativeValue }; + _Host = nativeValue; } _flag0 |= 0x100000u; } @@ -543,7 +544,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] IfMatch + internal StringValues IfMatch { get { @@ -552,7 +553,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfMatch); if (nativeValue != null) { - _IfMatch = new string[] { nativeValue }; + _IfMatch = nativeValue; } _flag0 |= 0x200000u; } @@ -565,7 +566,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] IfModifiedSince + internal StringValues IfModifiedSince { get { @@ -574,7 +575,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfModifiedSince); if (nativeValue != null) { - _IfModifiedSince = new string[] { nativeValue }; + _IfModifiedSince = nativeValue; } _flag0 |= 0x400000u; } @@ -587,7 +588,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] IfNoneMatch + internal StringValues IfNoneMatch { get { @@ -596,7 +597,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfNoneMatch); if (nativeValue != null) { - _IfNoneMatch = new string[] { nativeValue }; + _IfNoneMatch = nativeValue; } _flag0 |= 0x800000u; } @@ -609,7 +610,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] IfRange + internal StringValues IfRange { get { @@ -618,7 +619,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfRange); if (nativeValue != null) { - _IfRange = new string[] { nativeValue }; + _IfRange = nativeValue; } _flag0 |= 0x1000000u; } @@ -631,7 +632,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] IfUnmodifiedSince + internal StringValues IfUnmodifiedSince { get { @@ -640,7 +641,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.IfUnmodifiedSince); if (nativeValue != null) { - _IfUnmodifiedSince = new string[] { nativeValue }; + _IfUnmodifiedSince = nativeValue; } _flag0 |= 0x2000000u; } @@ -653,7 +654,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] KeepAlive + internal StringValues KeepAlive { get { @@ -662,7 +663,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.KeepAlive); if (nativeValue != null) { - _KeepAlive = new string[] { nativeValue }; + _KeepAlive = nativeValue; } _flag0 |= 0x4000000u; } @@ -675,7 +676,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] LastModified + internal StringValues LastModified { get { @@ -684,7 +685,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.LastModified); if (nativeValue != null) { - _LastModified = new string[] { nativeValue }; + _LastModified = nativeValue; } _flag0 |= 0x8000000u; } @@ -697,7 +698,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] MaxForwards + internal StringValues MaxForwards { get { @@ -706,7 +707,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.MaxForwards); if (nativeValue != null) { - _MaxForwards = new string[] { nativeValue }; + _MaxForwards = nativeValue; } _flag0 |= 0x10000000u; } @@ -719,7 +720,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Pragma + internal StringValues Pragma { get { @@ -728,7 +729,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Pragma); if (nativeValue != null) { - _Pragma = new string[] { nativeValue }; + _Pragma = nativeValue; } _flag0 |= 0x20000000u; } @@ -741,7 +742,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] ProxyAuthorization + internal StringValues ProxyAuthorization { get { @@ -750,7 +751,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.ProxyAuthorization); if (nativeValue != null) { - _ProxyAuthorization = new string[] { nativeValue }; + _ProxyAuthorization = nativeValue; } _flag0 |= 0x40000000u; } @@ -763,7 +764,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Range + internal StringValues Range { get { @@ -772,7 +773,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Range); if (nativeValue != null) { - _Range = new string[] { nativeValue }; + _Range = nativeValue; } _flag0 |= 0x80000000u; } @@ -785,7 +786,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Referer + internal StringValues Referer { get { @@ -794,7 +795,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Referer); if (nativeValue != null) { - _Referer = new string[] { nativeValue }; + _Referer = nativeValue; } _flag1 |= 0x1u; } @@ -807,7 +808,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Te + internal StringValues Te { get { @@ -816,7 +817,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Te); if (nativeValue != null) { - _Te = new string[] { nativeValue }; + _Te = nativeValue; } _flag1 |= 0x2u; } @@ -829,7 +830,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Trailer + internal StringValues Trailer { get { @@ -838,7 +839,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Trailer); if (nativeValue != null) { - _Trailer = new string[] { nativeValue }; + _Trailer = nativeValue; } _flag1 |= 0x4u; } @@ -851,7 +852,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] TransferEncoding + internal StringValues TransferEncoding { get { @@ -860,7 +861,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.TransferEncoding); if (nativeValue != null) { - _TransferEncoding = new string[] { nativeValue }; + _TransferEncoding = nativeValue; } _flag1 |= 0x8u; } @@ -873,7 +874,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Translate + internal StringValues Translate { get { @@ -882,7 +883,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Translate); if (nativeValue != null) { - _Translate = new string[] { nativeValue }; + _Translate = nativeValue; } _flag1 |= 0x10u; } @@ -895,7 +896,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Upgrade + internal StringValues Upgrade { get { @@ -904,7 +905,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Upgrade); if (nativeValue != null) { - _Upgrade = new string[] { nativeValue }; + _Upgrade = nativeValue; } _flag1 |= 0x20u; } @@ -917,7 +918,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] UserAgent + internal StringValues UserAgent { get { @@ -926,7 +927,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.UserAgent); if (nativeValue != null) { - _UserAgent = new string[] { nativeValue }; + _UserAgent = nativeValue; } _flag1 |= 0x40u; } @@ -939,7 +940,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Via + internal StringValues Via { get { @@ -948,7 +949,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Via); if (nativeValue != null) { - _Via = new string[] { nativeValue }; + _Via = nativeValue; } _flag1 |= 0x80u; } @@ -961,7 +962,7 @@ namespace Microsoft.Net.Http.Server } } - internal string[] Warning + internal StringValues Warning { get { @@ -970,7 +971,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(HttpSysRequestHeader.Warning); if (nativeValue != null) { - _Warning = new string[] { nativeValue }; + _Warning = nativeValue; } _flag1 |= 0x100u; } @@ -1189,7 +1190,7 @@ namespace Microsoft.Net.Http.Server return false; } - private bool PropertiesTryGetValue(string key, out string[] value) + private bool PropertiesTryGetValue(string key, out StringValues value) { switch (key.Length) { @@ -1433,11 +1434,11 @@ namespace Microsoft.Net.Http.Server } break; } - value = null; + value = StringValues.Empty; return false; } - private bool PropertiesTrySetValue(string key, string[] value) + private bool PropertiesTrySetValue(string key, StringValues value) { switch (key.Length) { @@ -1734,7 +1735,7 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Te", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x2u) != 0); - Te = null; + Te = StringValues.Empty; return wasSet; } break; @@ -1743,7 +1744,7 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Via", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x80u) != 0); - Via = null; + Via = StringValues.Empty; return wasSet; } break; @@ -1752,21 +1753,21 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Date", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10000u) != 0); - Date = null; + Date = StringValues.Empty; return wasSet; } if (_From != null && string.Equals(key, "From", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80000u) != 0); - From = null; + From = StringValues.Empty; return wasSet; } if (_Host != null && string.Equals(key, "Host", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x100000u) != 0); - Host = null; + Host = StringValues.Empty; return wasSet; } break; @@ -1775,14 +1776,14 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Allow", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10u) != 0); - Allow = null; + Allow = StringValues.Empty; return wasSet; } if (_Range != null && string.Equals(key, "Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80000000u) != 0); - Range = null; + Range = StringValues.Empty; return wasSet; } break; @@ -1791,28 +1792,28 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Accept", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1u) != 0); - Accept = null; + Accept = StringValues.Empty; return wasSet; } if (_Cookie != null && string.Equals(key, "Cookie", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8000u) != 0); - Cookie = null; + Cookie = StringValues.Empty; return wasSet; } if (_Expect != null && string.Equals(key, "Expect", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20000u) != 0); - Expect = null; + Expect = StringValues.Empty; return wasSet; } if (_Pragma != null && string.Equals(key, "Pragma", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20000000u) != 0); - Pragma = null; + Pragma = StringValues.Empty; return wasSet; } break; @@ -1821,35 +1822,35 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Expires", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40000u) != 0); - Expires = null; + Expires = StringValues.Empty; return wasSet; } if (_Referer != null && string.Equals(key, "Referer", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x1u) != 0); - Referer = null; + Referer = StringValues.Empty; return wasSet; } if (_Trailer != null && string.Equals(key, "Trailer", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x4u) != 0); - Trailer = null; + Trailer = StringValues.Empty; return wasSet; } if (_Upgrade != null && string.Equals(key, "Upgrade", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x20u) != 0); - Upgrade = null; + Upgrade = StringValues.Empty; return wasSet; } if (_Warning != null && string.Equals(key, "Warning", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x100u) != 0); - Warning = null; + Warning = StringValues.Empty; return wasSet; } break; @@ -1858,14 +1859,14 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "If-Match", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x200000u) != 0); - IfMatch = null; + IfMatch = StringValues.Empty; return wasSet; } if (_IfRange != null && string.Equals(key, "If-Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1000000u) != 0); - IfRange = null; + IfRange = StringValues.Empty; return wasSet; } break; @@ -1874,7 +1875,7 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Translate", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x10u) != 0); - Translate = null; + Translate = StringValues.Empty; return wasSet; } break; @@ -1883,21 +1884,21 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Connection", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80u) != 0); - Connection = null; + Connection = StringValues.Empty; return wasSet; } if (_KeepAlive != null && string.Equals(key, "Keep-Alive", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4000000u) != 0); - KeepAlive = null; + KeepAlive = StringValues.Empty; return wasSet; } if (_UserAgent != null && string.Equals(key, "User-Agent", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x40u) != 0); - UserAgent = null; + UserAgent = StringValues.Empty; return wasSet; } break; @@ -1906,7 +1907,7 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Content-Md5", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1000u) != 0); - ContentMd5 = null; + ContentMd5 = StringValues.Empty; return wasSet; } break; @@ -1915,14 +1916,14 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Content-Type", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4000u) != 0); - ContentType = null; + ContentType = StringValues.Empty; return wasSet; } if (_MaxForwards != null && string.Equals(key, "Max-Forwards", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10000000u) != 0); - MaxForwards = null; + MaxForwards = StringValues.Empty; return wasSet; } break; @@ -1931,35 +1932,35 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Authorization", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20u) != 0); - Authorization = null; + Authorization = StringValues.Empty; return wasSet; } if (_CacheControl != null && string.Equals(key, "Cache-Control", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40u) != 0); - CacheControl = null; + CacheControl = StringValues.Empty; return wasSet; } if (_ContentRange != null && string.Equals(key, "Content-Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2000u) != 0); - ContentRange = null; + ContentRange = StringValues.Empty; return wasSet; } if (_IfNoneMatch != null && string.Equals(key, "If-None-Match", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x800000u) != 0); - IfNoneMatch = null; + IfNoneMatch = StringValues.Empty; return wasSet; } if (_LastModified != null && string.Equals(key, "Last-Modified", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8000000u) != 0); - LastModified = null; + LastModified = StringValues.Empty; return wasSet; } break; @@ -1968,14 +1969,14 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Accept-Charset", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2u) != 0); - AcceptCharset = null; + AcceptCharset = StringValues.Empty; return wasSet; } if (_ContentLength != null && string.Equals(key, "Content-Length", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x400u) != 0); - ContentLength = null; + ContentLength = StringValues.Empty; return wasSet; } break; @@ -1984,14 +1985,14 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Accept-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4u) != 0); - AcceptEncoding = null; + AcceptEncoding = StringValues.Empty; return wasSet; } if (_AcceptLanguage != null && string.Equals(key, "Accept-Language", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8u) != 0); - AcceptLanguage = null; + AcceptLanguage = StringValues.Empty; return wasSet; } break; @@ -2000,21 +2001,21 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "Content-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x100u) != 0); - ContentEncoding = null; + ContentEncoding = StringValues.Empty; return wasSet; } if (_ContentLanguage != null && string.Equals(key, "Content-Language", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x200u) != 0); - ContentLanguage = null; + ContentLanguage = StringValues.Empty; return wasSet; } if (_ContentLocation != null && string.Equals(key, "Content-Location", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x800u) != 0); - ContentLocation = null; + ContentLocation = StringValues.Empty; return wasSet; } break; @@ -2023,14 +2024,14 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "If-Modified-Since", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x400000u) != 0); - IfModifiedSince = null; + IfModifiedSince = StringValues.Empty; return wasSet; } if (_TransferEncoding != null && string.Equals(key, "Transfer-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x8u) != 0); - TransferEncoding = null; + TransferEncoding = StringValues.Empty; return wasSet; } break; @@ -2039,14 +2040,14 @@ namespace Microsoft.Net.Http.Server && string.Equals(key, "If-Unmodified-Since", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2000000u) != 0); - IfUnmodifiedSince = null; + IfUnmodifiedSince = StringValues.Empty; return wasSet; } if (_ProxyAuthorization != null && string.Equals(key, "Proxy-Authorization", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40000000u) != 0); - ProxyAuthorization = null; + ProxyAuthorization = StringValues.Empty; return wasSet; } break; @@ -2222,7 +2223,7 @@ namespace Microsoft.Net.Http.Server } } - private IEnumerable PropertiesValues() + private IEnumerable PropertiesValues() { if (Accept != null) { @@ -2390,171 +2391,171 @@ namespace Microsoft.Net.Http.Server } } - private IEnumerable> PropertiesEnumerable() + private IEnumerable> PropertiesEnumerable() { if (Accept != null) { - yield return new KeyValuePair("Accept", Accept); + yield return new KeyValuePair("Accept", Accept); } if (AcceptCharset != null) { - yield return new KeyValuePair("Accept-Charset", AcceptCharset); + yield return new KeyValuePair("Accept-Charset", AcceptCharset); } if (AcceptEncoding != null) { - yield return new KeyValuePair("Accept-Encoding", AcceptEncoding); + yield return new KeyValuePair("Accept-Encoding", AcceptEncoding); } if (AcceptLanguage != null) { - yield return new KeyValuePair("Accept-Language", AcceptLanguage); + yield return new KeyValuePair("Accept-Language", AcceptLanguage); } if (Allow != null) { - yield return new KeyValuePair("Allow", Allow); + yield return new KeyValuePair("Allow", Allow); } if (Authorization != null) { - yield return new KeyValuePair("Authorization", Authorization); + yield return new KeyValuePair("Authorization", Authorization); } if (CacheControl != null) { - yield return new KeyValuePair("Cache-Control", CacheControl); + yield return new KeyValuePair("Cache-Control", CacheControl); } if (Connection != null) { - yield return new KeyValuePair("Connection", Connection); + yield return new KeyValuePair("Connection", Connection); } if (ContentEncoding != null) { - yield return new KeyValuePair("Content-Encoding", ContentEncoding); + yield return new KeyValuePair("Content-Encoding", ContentEncoding); } if (ContentLanguage != null) { - yield return new KeyValuePair("Content-Language", ContentLanguage); + yield return new KeyValuePair("Content-Language", ContentLanguage); } if (ContentLength != null) { - yield return new KeyValuePair("Content-Length", ContentLength); + yield return new KeyValuePair("Content-Length", ContentLength); } if (ContentLocation != null) { - yield return new KeyValuePair("Content-Location", ContentLocation); + yield return new KeyValuePair("Content-Location", ContentLocation); } if (ContentMd5 != null) { - yield return new KeyValuePair("Content-Md5", ContentMd5); + yield return new KeyValuePair("Content-Md5", ContentMd5); } if (ContentRange != null) { - yield return new KeyValuePair("Content-Range", ContentRange); + yield return new KeyValuePair("Content-Range", ContentRange); } if (ContentType != null) { - yield return new KeyValuePair("Content-Type", ContentType); + yield return new KeyValuePair("Content-Type", ContentType); } if (Cookie != null) { - yield return new KeyValuePair("Cookie", Cookie); + yield return new KeyValuePair("Cookie", Cookie); } if (Date != null) { - yield return new KeyValuePair("Date", Date); + yield return new KeyValuePair("Date", Date); } if (Expect != null) { - yield return new KeyValuePair("Expect", Expect); + yield return new KeyValuePair("Expect", Expect); } if (Expires != null) { - yield return new KeyValuePair("Expires", Expires); + yield return new KeyValuePair("Expires", Expires); } if (From != null) { - yield return new KeyValuePair("From", From); + yield return new KeyValuePair("From", From); } if (Host != null) { - yield return new KeyValuePair("Host", Host); + yield return new KeyValuePair("Host", Host); } if (IfMatch != null) { - yield return new KeyValuePair("If-Match", IfMatch); + yield return new KeyValuePair("If-Match", IfMatch); } if (IfModifiedSince != null) { - yield return new KeyValuePair("If-Modified-Since", IfModifiedSince); + yield return new KeyValuePair("If-Modified-Since", IfModifiedSince); } if (IfNoneMatch != null) { - yield return new KeyValuePair("If-None-Match", IfNoneMatch); + yield return new KeyValuePair("If-None-Match", IfNoneMatch); } if (IfRange != null) { - yield return new KeyValuePair("If-Range", IfRange); + yield return new KeyValuePair("If-Range", IfRange); } if (IfUnmodifiedSince != null) { - yield return new KeyValuePair("If-Unmodified-Since", IfUnmodifiedSince); + yield return new KeyValuePair("If-Unmodified-Since", IfUnmodifiedSince); } if (KeepAlive != null) { - yield return new KeyValuePair("Keep-Alive", KeepAlive); + yield return new KeyValuePair("Keep-Alive", KeepAlive); } if (LastModified != null) { - yield return new KeyValuePair("Last-Modified", LastModified); + yield return new KeyValuePair("Last-Modified", LastModified); } if (MaxForwards != null) { - yield return new KeyValuePair("Max-Forwards", MaxForwards); + yield return new KeyValuePair("Max-Forwards", MaxForwards); } if (Pragma != null) { - yield return new KeyValuePair("Pragma", Pragma); + yield return new KeyValuePair("Pragma", Pragma); } if (ProxyAuthorization != null) { - yield return new KeyValuePair("Proxy-Authorization", ProxyAuthorization); + yield return new KeyValuePair("Proxy-Authorization", ProxyAuthorization); } if (Range != null) { - yield return new KeyValuePair("Range", Range); + yield return new KeyValuePair("Range", Range); } if (Referer != null) { - yield return new KeyValuePair("Referer", Referer); + yield return new KeyValuePair("Referer", Referer); } if (Te != null) { - yield return new KeyValuePair("Te", Te); + yield return new KeyValuePair("Te", Te); } if (Trailer != null) { - yield return new KeyValuePair("Trailer", Trailer); + yield return new KeyValuePair("Trailer", Trailer); } if (TransferEncoding != null) { - yield return new KeyValuePair("Transfer-Encoding", TransferEncoding); + yield return new KeyValuePair("Transfer-Encoding", TransferEncoding); } if (Translate != null) { - yield return new KeyValuePair("Translate", Translate); + yield return new KeyValuePair("Translate", Translate); } if (Upgrade != null) { - yield return new KeyValuePair("Upgrade", Upgrade); + yield return new KeyValuePair("Upgrade", Upgrade); } if (UserAgent != null) { - yield return new KeyValuePair("User-Agent", UserAgent); + yield return new KeyValuePair("User-Agent", UserAgent); } if (Via != null) { - yield return new KeyValuePair("Via", Via); + yield return new KeyValuePair("Via", Via); } if (Warning != null) { - yield return new KeyValuePair("Warning", Warning); + yield return new KeyValuePair("Warning", Warning); } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt index 931380b1fd..a029f29b02 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt @@ -68,6 +68,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using Microsoft.Framework.Primitives; namespace Microsoft.Net.Http.Server { @@ -75,15 +76,15 @@ namespace Microsoft.Net.Http.Server internal partial class RequestHeaders { // Tracks if individual fields have been read from native or set directly. - // Once read or set, their presence in the collection is marked by if their string[] is null or not. + // Once read or set, their presence in the collection is marked by if their StringValues is null or not. private UInt32 _flag0, _flag1; <# foreach(var prop in props) { #> - private string[] _<#=prop.Name#>; + private StringValues _<#=prop.Name#>; <# } #> <# foreach(var prop in props) { #> - internal string[] <#=prop.Name#> + internal StringValues <#=prop.Name#> { get { @@ -92,7 +93,7 @@ namespace Microsoft.Net.Http.Server string nativeValue = GetKnownHeader(<#=prop.ID#>); if (nativeValue != null) { - _<#=prop.Name#> = new string[] { nativeValue }; + _<#=prop.Name#> = nativeValue; } <#=MarkRead(prop.Index)#>; } @@ -124,7 +125,7 @@ namespace Microsoft.Net.Http.Server return false; } - private bool PropertiesTryGetValue(string key, out string[] value) + private bool PropertiesTryGetValue(string key, out StringValues value) { switch (key.Length) { @@ -144,7 +145,7 @@ namespace Microsoft.Net.Http.Server return false; } - private bool PropertiesTrySetValue(string key, string[] value) + private bool PropertiesTrySetValue(string key, StringValues value) { switch (key.Length) { @@ -195,7 +196,7 @@ namespace Microsoft.Net.Http.Server <# } #> } - private IEnumerable PropertiesValues() + private IEnumerable PropertiesValues() { <# foreach(var prop in props) { #> if (<#=prop.Name#> != null) @@ -205,12 +206,12 @@ namespace Microsoft.Net.Http.Server <# } #> } - private IEnumerable> PropertiesEnumerable() + private IEnumerable> PropertiesEnumerable() { <# foreach(var prop in props) { #> if (<#=prop.Name#> != null) { - yield return new KeyValuePair("<#=prop.Key#>", <#=prop.Name#>); + yield return new KeyValuePair("<#=prop.Key#>", <#=prop.Name#>); } <# } #> } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs index 95e754870a..cc00e29da1 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs @@ -39,12 +39,13 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; +using Microsoft.Framework.Primitives; namespace Microsoft.Net.Http.Server { - internal partial class RequestHeaders : IDictionary + internal partial class RequestHeaders : IDictionary { - private IDictionary _extra; + private IDictionary _extra; private NativeRequestContext _requestMemoryBlob; internal RequestHeaders(NativeRequestContext requestMemoryBlob) @@ -52,13 +53,13 @@ namespace Microsoft.Net.Http.Server _requestMemoryBlob = requestMemoryBlob; } - private IDictionary Extra + private IDictionary Extra { get { if (_extra == null) { - var newDict = new Dictionary(StringComparer.OrdinalIgnoreCase); + var newDict = new Dictionary(StringComparer.OrdinalIgnoreCase); GetUnknownHeaders(newDict); Interlocked.CompareExchange(ref _extra, newDict, null); } @@ -66,11 +67,11 @@ namespace Microsoft.Net.Http.Server } } - string[] IDictionary.this[string key] + StringValues IDictionary.this[string key] { get { - string[] value; + StringValues value; return PropertiesTryGetValue(key, out value) ? value : Extra[key]; } set @@ -88,13 +89,13 @@ namespace Microsoft.Net.Http.Server _requestMemoryBlob.OriginalBlobAddress, (int)header); } - private void GetUnknownHeaders(IDictionary extra) + private void GetUnknownHeaders(IDictionary extra) { UnsafeNclNativeMethods.HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer, _requestMemoryBlob.OriginalBlobAddress); } - void IDictionary.Add(string key, string[] value) + void IDictionary.Add(string key, StringValues value) { if (!PropertiesTrySetValue(key, value)) { @@ -112,7 +113,7 @@ namespace Microsoft.Net.Http.Server get { return PropertiesKeys().Concat(Extra.Keys).ToArray(); } } - ICollection IDictionary.Values + ICollection IDictionary.Values { get { return PropertiesValues().Concat(Extra.Values).ToArray(); } } @@ -130,17 +131,17 @@ namespace Microsoft.Net.Http.Server return PropertiesTryRemove(key) || Extra.Remove(key); } - public bool TryGetValue(string key, out string[] value) + public bool TryGetValue(string key, out StringValues value) { return PropertiesTryGetValue(key, out value) || Extra.TryGetValue(key, out value); } - void ICollection>.Add(KeyValuePair item) + void ICollection>.Add(KeyValuePair item) { ((IDictionary)this).Add(item.Key, item.Value); } - void ICollection>.Clear() + void ICollection>.Clear() { foreach (var key in PropertiesKeys()) { @@ -149,36 +150,36 @@ namespace Microsoft.Net.Http.Server Extra.Clear(); } - bool ICollection>.Contains(KeyValuePair item) + bool ICollection>.Contains(KeyValuePair item) { object value; return ((IDictionary)this).TryGetValue(item.Key, out value) && Object.Equals(value, item.Value); } - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { PropertiesEnumerable().Concat(Extra).ToArray().CopyTo(array, arrayIndex); } - bool ICollection>.IsReadOnly + bool ICollection>.IsReadOnly { get { return false; } } - bool ICollection>.Remove(KeyValuePair item) + bool ICollection>.Remove(KeyValuePair item) { - return ((IDictionary)this).Contains(item) && - ((IDictionary)this).Remove(item.Key); + return ((IDictionary)this).Contains(item) && + ((IDictionary)this).Remove(item.Key); } - IEnumerator> IEnumerable>.GetEnumerator() + IEnumerator> IEnumerable>.GetEnumerator() { return PropertiesEnumerable().Concat(Extra).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { - return ((IDictionary)this).GetEnumerator(); + return ((IDictionary)this).GetEnumerator(); } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 487aa46cdc..8648b3bce5 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -33,14 +33,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Framework.Logging; +using Microsoft.Framework.Primitives; using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; namespace Microsoft.Net.Http.Server { public sealed unsafe class Response { - private static readonly string[] ZeroContentLength = new[] { Constants.Zero }; - private ResponseState _responseState; private HeaderCollection _headers; private string _reasonPhrase; @@ -200,7 +199,7 @@ namespace Microsoft.Net.Http.Server { get { - string contentLengthString = Headers.Get(HttpKnownHeaderNames.ContentLength); + string contentLengthString = Headers[HttpKnownHeaderNames.ContentLength]; long contentLength; if (!string.IsNullOrWhiteSpace(contentLengthString)) { @@ -232,7 +231,7 @@ namespace Microsoft.Net.Http.Server if (value.Value == 0) { - ((IDictionary)Headers)[HttpKnownHeaderNames.ContentLength] = ZeroContentLength; + Headers[HttpKnownHeaderNames.ContentLength] = Constants.Zero; } else { @@ -246,7 +245,7 @@ namespace Microsoft.Net.Http.Server { get { - return Headers.Get(HttpKnownHeaderNames.ContentType); + return Headers[HttpKnownHeaderNames.ContentType]; } set { @@ -467,14 +466,14 @@ namespace Microsoft.Net.Http.Server // Gather everything from the request that affects the response: var requestVersion = Request.ProtocolVersion; - var requestConnectionString = Request.Headers.Get(HttpKnownHeaderNames.Connection); + var requestConnectionString = Request.Headers[HttpKnownHeaderNames.Connection]; var isHeadRequest = Request.IsHeadMethod; var requestCloseSet = Matches(Constants.Close, requestConnectionString); // Gather everything the app may have set on the response: // Http.Sys does not allow us to specify the response protocol version, assume this is a HTTP/1.1 response when making decisions. - var responseConnectionString = Headers.Get(HttpKnownHeaderNames.Connection); - var transferEncodingString = Headers.Get(HttpKnownHeaderNames.TransferEncoding); + var responseConnectionString = Headers[HttpKnownHeaderNames.Connection]; + var transferEncodingString = Headers[HttpKnownHeaderNames.TransferEncoding]; var responseContentLength = ContentLength; var responseCloseSet = Matches(Constants.Close, responseConnectionString); var responseChunkedSet = Matches(Constants.Chunked, transferEncodingString); @@ -572,9 +571,9 @@ namespace Microsoft.Net.Http.Server int numUnknownHeaders = 0; int numKnownMultiHeaders = 0; - foreach (KeyValuePair headerPair in Headers) + foreach (var headerPair in Headers) { - if (headerPair.Value.Length == 0) + if (headerPair.Value.Count == 0) { // TODO: Have the collection exclude empty headers. continue; @@ -586,9 +585,9 @@ namespace Microsoft.Net.Http.Server if (lookup == -1 || (isOpaqueUpgrade && lookup == (int)HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { - numUnknownHeaders += headerPair.Value.Length; + numUnknownHeaders += headerPair.Value.Count; } - else if (headerPair.Value.Length > 1) + else if (headerPair.Value.Count > 1) { numKnownMultiHeaders++; } @@ -599,15 +598,15 @@ namespace Microsoft.Net.Http.Server { fixed (HttpApi.HTTP_KNOWN_HEADER* pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders) { - foreach (KeyValuePair headerPair in Headers) + foreach (var headerPair in Headers) { - if (headerPair.Value.Length == 0) + if (headerPair.Value.Count == 0) { // TODO: Have the collection exclude empty headers. continue; } headerName = headerPair.Key; - string[] headerValues = headerPair.Value; + StringValues headerValues = headerPair.Value; lookup = HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. @@ -622,7 +621,7 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.Headers.pUnknownHeaders = (HttpApi.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); } - for (int headerValueIndex = 0; headerValueIndex < headerValues.Length; headerValueIndex++) + for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Name bytes = new byte[HeaderEncoding.GetByteCount(headerName)]; @@ -643,7 +642,7 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.Headers.UnknownHeaderCount++; } } - else if (headerPair.Value.Length == 1) + else if (headerPair.Value.Count == 1) { headerValue = headerValues[0]; if (headerValue != null) @@ -674,12 +673,12 @@ namespace Microsoft.Net.Http.Server header.HeaderId = (HttpApi.HTTP_RESPONSE_HEADER_ID.Enum)lookup; header.Flags = HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only. - HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApi.HTTP_KNOWN_HEADER[headerValues.Length]; + HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApi.HTTP_KNOWN_HEADER[headerValues.Count]; gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); header.KnownHeaders = (HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); - for (int headerValueIndex = 0; headerValueIndex < headerValues.Length; headerValueIndex++) + for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Value headerValue = headerValues[headerValueIndex]; diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 8356811d61..ac42adf57d 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -3,6 +3,7 @@ "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", + "Microsoft.Framework.Primitives": "1.0.0-*", "Microsoft.Net.WebSockets": "1.0.0-*" }, "compilationOptions": { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index fcf661891f..c8e1302986 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -22,6 +22,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; +using Microsoft.Framework.Primitives; using Xunit; namespace Microsoft.AspNet.Server.WebListener @@ -38,8 +39,8 @@ namespace Microsoft.AspNet.Server.WebListener // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. // Assert.Equal(2, requestHeaders.Count); // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); - Assert.NotNull(requestHeaders.Get("Host")); - Assert.Equal(null, requestHeaders.Get("Accept")); + Assert.False(StringValues.IsNullOrEmpty(requestHeaders["Host"])); + Assert.True(StringValues.IsNullOrEmpty(requestHeaders["Accept"])); return Task.FromResult(0); })) { @@ -56,13 +57,13 @@ namespace Microsoft.AspNet.Server.WebListener { var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; Assert.Equal(4, requestHeaders.Count); - Assert.NotNull(requestHeaders.Get("Host")); - Assert.Equal("close", requestHeaders.Get("Connection")); + Assert.False(StringValues.IsNullOrEmpty(requestHeaders["Host"])); + Assert.Equal("close", requestHeaders["Connection"]); // Apparently Http.Sys squashes request headers together. - Assert.Equal(1, requestHeaders.GetValues("Custom-Header").Count); - Assert.Equal("custom1, and custom2, custom3", requestHeaders.Get("Custom-Header")); - Assert.Equal(1, requestHeaders.GetValues("Spacer-Header").Count); - Assert.Equal("spacervalue, spacervalue", requestHeaders.Get("Spacer-Header")); + Assert.Equal(1, requestHeaders["Custom-Header"].Count); + Assert.Equal("custom1, and custom2, custom3", requestHeaders["Custom-Header"]); + Assert.Equal(1, requestHeaders["Spacer-Header"].Count); + Assert.Equal("spacervalue, spacervalue", requestHeaders["Spacer-Header"]); return Task.FromResult(0); })) { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index 73eb3d152e..dd47057415 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Microsoft.Framework.Primitives; using Xunit; namespace Microsoft.Net.Http.Server @@ -26,10 +27,10 @@ namespace Microsoft.Net.Http.Server // Assert.Equal(2, requestHeaders.Count); // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); - string[] values; + StringValues values; Assert.False(requestHeaders.TryGetValue("Accept", out values)); Assert.False(requestHeaders.ContainsKey("Accept")); - Assert.Null(requestHeaders["Accept"]); + Assert.True(StringValues.IsNullOrEmpty(requestHeaders["Accept"])); context.Dispose(); string response = await responseTask; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index 2f6648aaf3..46c471c607 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -207,7 +207,7 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders.SetValues("WWW-Authenticate", "custom1, and custom2", "custom3"); + responseHeaders["WWW-Authenticate"] = new[] { "custom1, and custom2", "custom3" }; context.Dispose(); // HttpClient would merge the headers no matter what @@ -232,7 +232,7 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders.SetValues("Custom-Header1", "custom1, and custom2", "custom3"); + responseHeaders["Custom-Header1"] = new[] { "custom1, and custom2", "custom3" }; context.Dispose(); // HttpClient would merge the headers no matter what @@ -346,8 +346,8 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders.SetValues("Custom1", "value1a", "value1b"); - responseHeaders.SetValues("Custom2", "value2a, value2b"); + responseHeaders["Custom1"] = new[] { "value1a", "value1b" }; + responseHeaders["Custom2"] = "value2a, value2b"; var body = context.Response.Body; Assert.False(context.Response.HasStarted); body.Flush(); @@ -382,8 +382,8 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); var responseHeaders = context.Response.Headers; - responseHeaders.SetValues("Custom1", "value1a", "value1b"); - responseHeaders.SetValues("Custom2", "value2a, value2b"); + responseHeaders["Custom1"] = new[] { "value1a", "value1b" }; + responseHeaders["Custom2"] = "value2a, value2b"; var body = context.Response.Body; Assert.False(context.Response.HasStarted); await body.FlushAsync(); From 195e06970a225efb8c4df635f98859a62bae0dfa Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 31 Aug 2015 07:31:43 -0700 Subject: [PATCH 244/597] Use new HttpContext.Features API. --- .../HttpsTests.cs | 4 +-- .../OpaqueUpgradeTests.cs | 10 +++---- .../RequestTests.cs | 16 ++++++------ .../ResponseHeaderTests.cs | 14 +++++----- .../ResponseSendFileTests.cs | 26 +++++++++---------- .../ResponseTests.cs | 2 +- .../WebSocketTests.cs | 8 +++--- 7 files changed, 40 insertions(+), 40 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 4078d411b5..4ac233d4a4 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var tls = httpContext.GetFeature(); + var tls = httpContext.Features.Get(); Assert.NotNull(tls); var cert = await tls.GetClientCertificateAsync(CancellationToken.None); Assert.Null(cert); @@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpsServer(async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var tls = httpContext.GetFeature(); + var tls = httpContext.Features.Get(); Assert.NotNull(tls); var cert = await tls.GetClientCertificateAsync(CancellationToken.None); Assert.NotNull(cert); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 0ed71d2efb..acdb509cad 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.Features.Get(); Assert.NotNull(opaqueFeature); } catch (Exception ex) @@ -73,7 +73,7 @@ namespace Microsoft.AspNet.Server.WebListener await httpContext.Response.Body.FlushAsync(); try { - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.Features.Get(); Assert.NotNull(opaqueFeature); await opaqueFeature.UpgradeAsync(); upgradeThrew = false; @@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.Features.Get(); Assert.NotNull(opaqueFeature); Assert.True(opaqueFeature.IsUpgradableRequest); await opaqueFeature.UpgradeAsync(); @@ -152,7 +152,7 @@ namespace Microsoft.AspNet.Server.WebListener try { httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.Features.Get(); Assert.NotNull(opaqueFeature); Assert.True(opaqueFeature.IsUpgradableRequest); var opaqueStream = await opaqueFeature.UpgradeAsync(); @@ -195,7 +195,7 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - var opaqueFeature = httpContext.GetFeature(); + var opaqueFeature = httpContext.Features.Get(); Assert.NotNull(opaqueFeature); Assert.False(opaqueFeature.IsUpgradableRequest); } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 898552b1be..a352b9c4c0 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - var requestInfo = httpContext.GetFeature(); + var requestInfo = httpContext.Features.Get(); // Request Keys Assert.Equal("GET", requestInfo.Method); @@ -55,7 +55,7 @@ namespace Microsoft.AspNet.Server.WebListener // Server Keys // TODO: Assert.NotNull(env.Get>("server.Capabilities")); - var connectionInfo = httpContext.GetFeature(); + var connectionInfo = httpContext.Features.Get(); Assert.Equal("::1", connectionInfo.RemoteIpAddress.ToString()); Assert.NotEqual(0, connectionInfo.RemotePort); Assert.Equal("::1", connectionInfo.LocalIpAddress.ToString()); @@ -63,7 +63,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.True(connectionInfo.IsLocal); // Trace identifier - var requestIdentifierFeature = httpContext.GetFeature(); + var requestIdentifierFeature = httpContext.Features.Get(); Assert.NotNull(requestIdentifierFeature); Assert.NotNull(requestIdentifierFeature.TraceIdentifier); @@ -97,9 +97,9 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - var requestInfo = httpContext.GetFeature(); - var connectionInfo = httpContext.GetFeature(); - var requestIdentifierFeature = httpContext.GetFeature(); + var requestInfo = httpContext.Features.Get(); + var connectionInfo = httpContext.Features.Get(); + var requestIdentifierFeature = httpContext.Features.Get(); // Request Keys Assert.Equal("http", requestInfo.Scheme); @@ -143,8 +143,8 @@ namespace Microsoft.AspNet.Server.WebListener using (CreateServer(out root, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var requestInfo = httpContext.GetFeature(); - var requestIdentifierFeature = httpContext.GetFeature(); + var requestInfo = httpContext.Features.Get(); + var requestIdentifierFeature = httpContext.Features.Get(); try { Assert.Equal(expectedPath, requestInfo.Path); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 27726324c7..f0db3b7557 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["WWW-Authenticate"] = new string[] { "custom1" }; return Task.FromResult(0); @@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["WWW-Authenticate"] = new string[] { "custom1, and custom2", "custom3" }; return Task.FromResult(0); @@ -107,7 +107,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["Custom-Header1"] = new string[] { "custom1, and custom2", "custom3" }; return Task.FromResult(0); @@ -132,7 +132,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["Connection"] = new string[] { "Close" }; httpContext.Response.Body.Flush(); // Http.Sys adds the Content-Length: header for us if we don't flush @@ -180,7 +180,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["Transfer-Encoding"] = new string[] { "chunked" }; var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); @@ -210,7 +210,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); @@ -242,7 +242,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var responseInfo = httpContext.GetFeature(); + var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); responseHeaders.Add("Custom2", new string[] { "value2a, value2b" }); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 63841ac0b4..c52ffc8446 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal("Overlapped", support.Get("sendfile.Concurrency")); */ - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); Assert.NotNull(sendFile); } catch (Exception ex) @@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); try { sendFile.SendFileAsync(string.Empty, 0, null, CancellationToken.None).Wait(); @@ -127,7 +127,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { @@ -147,7 +147,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); })) { @@ -167,7 +167,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { @@ -187,7 +187,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None).Wait(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) @@ -208,7 +208,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); })) { @@ -228,7 +228,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); })) { @@ -244,7 +244,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); })) { @@ -260,7 +260,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) { @@ -280,7 +280,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); httpContext.Response.Headers["Content-lenGth"] = FileLength.ToString(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) @@ -302,7 +302,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); httpContext.Response.Headers["Content-lenGth"] = "10"; return sendFile.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); })) @@ -324,7 +324,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var sendFile = httpContext.GetFeature(); + var sendFile = httpContext.Features.Get(); httpContext.Response.Headers["Content-lenGth"] = "0"; return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index f3381a89c8..40ed9469b0 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Server.WebListener { var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 201; - httpContext.GetFeature().ReasonPhrase = "CustomReasonPhrase"; // TODO? + httpContext.Features.Get().ReasonPhrase = "CustomReasonPhrase"; // TODO? // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value return Task.FromResult(0); })) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index c13b6e56ff..09830bf3f3 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Server.WebListener var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { - var webSocketFeature = httpContext.GetFeature(); + var webSocketFeature = httpContext.Features.Get(); Assert.NotNull(webSocketFeature); } catch (Exception ex) @@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener await httpContext.Response.WriteAsync("Hello World"); try { - var webSocketFeature = httpContext.GetFeature(); + var webSocketFeature = httpContext.Features.Get(); Assert.NotNull(webSocketFeature); await webSocketFeature.AcceptAsync(null); upgradeThrew = false; @@ -97,7 +97,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var webSocketFeature = httpContext.GetFeature(); + var webSocketFeature = httpContext.Features.Get(); Assert.NotNull(webSocketFeature); Assert.True(webSocketFeature.IsWebSocketRequest); await webSocketFeature.AcceptAsync(null); @@ -123,7 +123,7 @@ namespace Microsoft.AspNet.Server.WebListener using (Utilities.CreateHttpServer(out address, async env => { var httpContext = new DefaultHttpContext((IFeatureCollection)env); - var webSocketFeature = httpContext.GetFeature(); + var webSocketFeature = httpContext.Features.Get(); Assert.NotNull(webSocketFeature); Assert.True(webSocketFeature.IsWebSocketRequest); var serverWebSocket = await webSocketFeature.AcceptAsync(null); From 0603a69b2c58816b04265e2142ebd3d9b9c478f3 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 31 Aug 2015 16:46:13 -0700 Subject: [PATCH 245/597] Convert IServerInformation to IFeatureCollection. --- samples/HotAddSample/Startup.cs | 5 +- samples/SelfHostServer/Startup.cs | 6 +- .../ServerFactory.cs | 25 ++++---- .../ServerInformation.cs | 60 ------------------- .../RequestTests.cs | 7 ++- .../ServerTests.cs | 12 ++-- .../Utilities.cs | 17 +++--- 7 files changed, 37 insertions(+), 95 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index e1424665a4..9064491c5b 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -1,7 +1,7 @@ using System; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Server.WebListener; +using Microsoft.AspNet.Http.Features; using Microsoft.Framework.Logging; namespace HotAddSample @@ -15,8 +15,7 @@ namespace HotAddSample { loggerfactory.AddConsole(LogLevel.Information); - var server = (ServerInformation)app.Server; - var listener = server.Listener; + var listener = app.ServerFeatures.Get(); listener.UrlPrefixes.Add("http://localhost:12346/pathBase/"); app.Use(async (context, next) => diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index a2948987dc..f7d41f42e5 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Server.WebListener; +using Microsoft.AspNet.Http.Features; using Microsoft.Framework.Logging; using Microsoft.Net.Http.Server; @@ -14,8 +14,8 @@ namespace SelfHostServer { public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { - var info = (ServerInformation)app.Server; - info.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; + var listener = app.ServerFeatures.Get(); + listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; loggerfactory.AddConsole(LogLevel.Verbose); diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 693106a9c9..accaf6372c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -64,11 +64,14 @@ namespace Microsoft.AspNet.Server.WebListener /// /// [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] - public IServerInformation Initialize(IConfiguration configuration) + public IFeatureCollection Initialize(IConfiguration configuration) { Microsoft.Net.Http.Server.WebListener listener = new Microsoft.Net.Http.Server.WebListener(_loggerFactory); ParseAddresses(configuration, listener); - return new ServerInformation(new MessagePump(listener, _loggerFactory)); + var serverFeatures = new FeatureCollection(); + serverFeatures.Set(listener); + serverFeatures.Set(new MessagePump(listener, _loggerFactory)); + return serverFeatures; } /// @@ -76,27 +79,25 @@ namespace Microsoft.AspNet.Server.WebListener /// The per-request application entry point. /// The value returned /// The server. Invoke Dispose to shut down. - public IDisposable Start(IServerInformation server, AppFunc app) + public IDisposable Start(IFeatureCollection serverFeatures, AppFunc app) { - if (server == null) + if (serverFeatures == null) { - throw new ArgumentNullException("server"); + throw new ArgumentNullException("serverFeatures"); } if (app == null) { throw new ArgumentNullException("app"); } - var serverInfo = server as ServerInformation; - if (serverInfo == null) + var messagePump = serverFeatures.Get(); + if (messagePump == null) { - throw new ArgumentException("server"); + throw new InvalidOperationException("messagePump"); } - // TODO: var capabilities = new Dictionary(); - - serverInfo.MessagePump.Start(app); - return serverInfo.MessagePump; + messagePump.Start(app); + return messagePump; } private void ParseAddresses(IConfiguration config, Microsoft.Net.Http.Server.WebListener listener) diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs b/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs deleted file mode 100644 index 9c50b466f8..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/ServerInformation.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -using System.Reflection; -using Microsoft.AspNet.Hosting.Server; - -namespace Microsoft.AspNet.Server.WebListener -{ - public class ServerInformation : IServerInformation - { - private MessagePump _messagePump; - - internal ServerInformation(MessagePump messagePump) - { - _messagePump = messagePump; - } - - internal MessagePump MessagePump - { - get { return _messagePump; } - } - - // Microsoft.AspNet.Server.WebListener - public string Name - { - get { return GetType().GetTypeInfo().Assembly.GetName().Name; } - } - - public Microsoft.Net.Http.Server.WebListener Listener - { - get { return _messagePump.Listener; } - } - - public int MaxAccepts - { - get { return _messagePump.MaxAccepts; } - set { _messagePump.MaxAccepts = value; } - } - - public bool EnableResponseCaching - { - get { return _messagePump.EnableResponseCaching; } - set { _messagePump.EnableResponseCaching = value; } - } - } -} diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index a352b9c4c0..0ebbfb6c00 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -174,14 +174,15 @@ namespace Microsoft.AspNet.Server.WebListener server.Dispose(); var rootUri = new Uri(root); var factory = new ServerFactory(loggerFactory: null); - var serverInfo = (ServerInformation)factory.Initialize(configuration: null); + var serverFeatures = factory.Initialize(configuration: null); + var listener = serverFeatures.Get(); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); + listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); } - return factory.Start(serverInfo, app); + return factory.Start(serverFeatures, app); } private async Task SendRequestAsync(string uri) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index e3299693f5..b787d5e96f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -253,17 +253,17 @@ namespace Microsoft.AspNet.Server.WebListener [Fact] public async Task Server_SetQueueLimit_Success() { - // TODO: This is just to get a dynamic port + // This is just to get a dynamic port string address; using (Utilities.CreateHttpServer(out address, env => Task.FromResult(0))) { } var factory = new ServerFactory(loggerFactory: null); - var serverInfo = (ServerInformation)factory.Initialize(configuration: null); - serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(address)); + var serverFeatures = factory.Initialize(configuration: null); + var listener = serverFeatures.Get(); + listener.UrlPrefixes.Add(UrlPrefix.Create(address)); + listener.SetRequestQueueLimit(1001); - serverInfo.Listener.SetRequestQueueLimit(1001); - - using (factory.Start(serverInfo, env => Task.FromResult(0))) + using (factory.Start(serverFeatures, env => Task.FromResult(0))) { string response = await SendRequestAsync(address); Assert.Equal(string.Empty, response); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index 5e70a77b50..e838ced3fb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -17,6 +17,7 @@ using System; using System.Threading.Tasks; +using Microsoft.AspNet.Http.Features; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener @@ -61,12 +62,13 @@ namespace Microsoft.AspNet.Server.WebListener root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; baseAddress = prefix.ToString(); - var serverInfo = (ServerInformation)factory.Initialize(configuration: null); - serverInfo.Listener.UrlPrefixes.Add(prefix); - serverInfo.Listener.AuthenticationManager.AuthenticationSchemes = authType; + var serverFeatures = factory.Initialize(configuration: null); + var listener = serverFeatures.Get(); + listener.UrlPrefixes.Add(prefix); + listener.AuthenticationManager.AuthenticationSchemes = authType; try { - return factory.Start(serverInfo, app); + return factory.Start(serverFeatures, app); } catch (WebListenerException) { @@ -85,10 +87,9 @@ namespace Microsoft.AspNet.Server.WebListener internal static IDisposable CreateServer(string scheme, string host, int port, string path, AppFunc app) { var factory = new ServerFactory(loggerFactory: null); - var serverInfo = (ServerInformation)factory.Initialize(configuration: null); - serverInfo.Listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); - - return factory.Start(serverInfo, app); + var serverFeatures = factory.Initialize(configuration: null); + serverFeatures.Get().UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); + return factory.Start(serverFeatures, app); } } } From 3a0182688a0dd0dfe22bc74a4186a270d1ff800d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 10 Sep 2015 18:44:15 -0700 Subject: [PATCH 246/597] Adding NeutralResourcesLanguageAttribute --- .../Properties/AssemblyInfo.cs | 4 +++- src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs | 4 +++- src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs index f5c6f4a83a..78dfe3c1e0 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs @@ -2,5 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Reflection; +using System.Resources; -[assembly: AssemblyMetadata("Serviceable", "True")] \ No newline at end of file +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs index f5c6f4a83a..78dfe3c1e0 100644 --- a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs @@ -2,5 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Reflection; +using System.Resources; -[assembly: AssemblyMetadata("Serviceable", "True")] \ No newline at end of file +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs b/src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs index f5c6f4a83a..78dfe3c1e0 100644 --- a/src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs @@ -2,5 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Reflection; +using System.Resources; -[assembly: AssemblyMetadata("Serviceable", "True")] \ No newline at end of file +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file From ce06872b84e73eabae3f97cb0847a367b03eec68 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 11 Sep 2015 14:00:58 -0700 Subject: [PATCH 247/597] Hosting#331 Add IServerAddressesFeature. --- samples/HotAddSample/Startup.cs | 11 +++---- .../ServerAddressesFeature.cs | 27 +++++++++++++++++ .../ServerFactory.cs | 30 +++++++++++++++---- src/Microsoft.Net.Http.Server/UrlPrefix.cs | 6 ++++ .../Utilities.cs | 3 +- 5 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 src/Microsoft.AspNet.Server.WebListener/ServerAddressesFeature.cs diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index 9064491c5b..e5026e9db9 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Server.Features; using Microsoft.Framework.Logging; namespace HotAddSample @@ -15,8 +16,8 @@ namespace HotAddSample { loggerfactory.AddConsole(LogLevel.Information); - var listener = app.ServerFeatures.Get(); - listener.UrlPrefixes.Add("http://localhost:12346/pathBase/"); + var addresses = app.ServerFeatures.Get().Addresses; + addresses.Add("http://localhost:12346/pathBase/"); app.Use(async (context, next) => { @@ -28,7 +29,7 @@ namespace HotAddSample await context.Response.WriteAsync(""); try { - listener.UrlPrefixes.Add(toAdd); + addresses.Add(toAdd); await context.Response.WriteAsync("Added: " + toAdd); } catch (Exception ex) @@ -52,7 +53,7 @@ namespace HotAddSample { context.Response.ContentType = "text/html"; await context.Response.WriteAsync(""); - if (listener.UrlPrefixes.Remove(toRemove)) + if (addresses.Remove(toRemove)) { await context.Response.WriteAsync("Removed: " + toRemove); } @@ -72,7 +73,7 @@ namespace HotAddSample context.Response.ContentType = "text/html"; await context.Response.WriteAsync(""); await context.Response.WriteAsync("Listening on these prefixes:
"); - foreach (var prefix in listener.UrlPrefixes) + foreach (var prefix in addresses) { await context.Response.WriteAsync("" + prefix + " (remove)
"); } diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerAddressesFeature.cs b/src/Microsoft.AspNet.Server.WebListener/ServerAddressesFeature.cs new file mode 100644 index 0000000000..d617baa7ea --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/ServerAddressesFeature.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System.Collections.Generic; +using Microsoft.AspNet.Server.Features; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class ServerAddressesFeature : IServerAddressesFeature + { + public ICollection Addresses { get; } = new List(); + } +} diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index accaf6372c..238c268df7 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -35,10 +35,12 @@ // limitations under the License. using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Server.Features; using Microsoft.Framework.Configuration; using Microsoft.Framework.Logging; using Microsoft.Net.Http.Server; @@ -67,10 +69,10 @@ namespace Microsoft.AspNet.Server.WebListener public IFeatureCollection Initialize(IConfiguration configuration) { Microsoft.Net.Http.Server.WebListener listener = new Microsoft.Net.Http.Server.WebListener(_loggerFactory); - ParseAddresses(configuration, listener); var serverFeatures = new FeatureCollection(); serverFeatures.Set(listener); serverFeatures.Set(new MessagePump(listener, _loggerFactory)); + serverFeatures.Set(SplitAddresses(configuration)); return serverFeatures; } @@ -96,22 +98,38 @@ namespace Microsoft.AspNet.Server.WebListener throw new InvalidOperationException("messagePump"); } + var addressesFeature = serverFeatures.Get(); + if (addressesFeature == null) + { + throw new InvalidOperationException("IServerAddressesFeature"); + } + + ParseAddresses(addressesFeature.Addresses, messagePump.Listener); + messagePump.Start(app); return messagePump; } - private void ParseAddresses(IConfiguration config, Microsoft.Net.Http.Server.WebListener listener) + private IServerAddressesFeature SplitAddresses(IConfiguration config) { - // TODO: Key format? + var addressesFeature = new ServerAddressesFeature(); if (config != null && !string.IsNullOrEmpty(config["server.urls"])) { var urls = config["server.urls"]; - foreach (var value in urls.Split(';')) + foreach (var value in urls.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { - listener.UrlPrefixes.Add(UrlPrefix.Create(value)); + addressesFeature.Addresses.Add(value); } } - // TODO: look for just a port option? + return addressesFeature; + } + + private void ParseAddresses(ICollection addresses, Microsoft.Net.Http.Server.WebListener listener) + { + foreach (var value in addresses) + { + listener.UrlPrefixes.Add(UrlPrefix.Create(value)); + } } } } diff --git a/src/Microsoft.Net.Http.Server/UrlPrefix.cs b/src/Microsoft.Net.Http.Server/UrlPrefix.cs index 0c53cc67c9..34689b9eac 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefix.cs @@ -122,6 +122,12 @@ namespace Microsoft.Net.Http.Server int delimiterStart1 = whole.IndexOf("://", StringComparison.Ordinal); if (delimiterStart1 < 0) { + int aPort; + if (int.TryParse(whole, NumberStyles.None, CultureInfo.InvariantCulture, out aPort)) + { + return UrlPrefix.Create("http", "localhost", aPort, "/"); + } + throw new FormatException("Invalid prefix, missing scheme separator: " + prefix); } int delimiterEnd1 = delimiterStart1 + "://".Length; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index e838ced3fb..899c18beea 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -18,6 +18,7 @@ using System; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Server.Features; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener @@ -88,7 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener { var factory = new ServerFactory(loggerFactory: null); var serverFeatures = factory.Initialize(configuration: null); - serverFeatures.Get().UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); + serverFeatures.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); return factory.Start(serverFeatures, app); } } From 8b3175e904cd485d58a4dc86ab2885647e6cc555 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 17 Sep 2015 18:32:54 -0700 Subject: [PATCH 248/597] Update nuget.exe and corresponding feeds to v3. --- NuGet.Config => NuGet.config | 2 +- build.cmd | 11 ++++++----- build.sh | 12 +++++++----- 3 files changed, 14 insertions(+), 11 deletions(-) rename NuGet.Config => NuGet.config (83%) diff --git a/NuGet.Config b/NuGet.config similarity index 83% rename from NuGet.Config rename to NuGet.config index 10cec18a32..1707938c61 100644 --- a/NuGet.Config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/build.cmd b/build.cmd index b54d91cf74..177997c42e 100644 --- a/build.cmd +++ b/build.cmd @@ -2,14 +2,15 @@ cd %~dp0 SETLOCAL -SET CACHED_NUGET=%LocalAppData%\NuGet\NuGet.exe +SET NUGET_VERSION=latest +SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe SET BUILDCMD_KOREBUILD_VERSION="" SET BUILDCMD_DNX_VERSION="" IF EXIST %CACHED_NUGET% goto copynuget echo Downloading latest version of NuGet.exe... IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet -@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://www.nuget.org/nuget.exe' -OutFile '%CACHED_NUGET%'" +@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" :copynuget IF EXIST .nuget\nuget.exe goto restore @@ -19,11 +20,11 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore IF EXIST packages\KoreBuild goto run IF %BUILDCMD_KOREBUILD_VERSION%=="" ( - .nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre ) ELSE ( - .nuget\NuGet.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre ) -.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages +.nuget\nuget.exe install Sake -ExcludeVersion -Out packages IF "%SKIP_DNX_INSTALL%"=="1" goto run IF %BUILDCMD_DNX_VERSION%=="" ( diff --git a/build.sh b/build.sh index 68c3e8cb52..0c66139817 100755 --- a/build.sh +++ b/build.sh @@ -10,21 +10,23 @@ else fi fi mkdir -p $cachedir +nugetVersion=latest +cachePath=$cachedir/nuget.$nugetVersion.exe -url=https://www.nuget.org/nuget.exe +url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe -if test ! -f $cachedir/nuget.exe; then - wget -O $cachedir/nuget.exe $url 2>/dev/null || curl -o $cachedir/nuget.exe --location $url /dev/null +if test ! -f $cachePath; then + wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null fi if test ! -e .nuget; then mkdir .nuget - cp $cachedir/nuget.exe .nuget/nuget.exe + cp $cachePath .nuget/nuget.exe fi if test ! -d packages/KoreBuild; then mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages + mono .nuget/nuget.exe install Sake -ExcludeVersion -Out packages fi if ! type dnvm > /dev/null 2>&1; then From 1ff204f47cd3872671eafaeb03b99c5bcca38a17 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Wed, 23 Sep 2015 15:21:53 -0700 Subject: [PATCH 249/597] React to Caption => DisplayName --- .../AuthenticationHandler.cs | 2 +- .../AuthenticationTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index d6f9ebd9ca..242fc3b707 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -137,7 +137,7 @@ namespace Microsoft.AspNet.Server.WebListener return new Dictionary() { { "AuthenticationScheme", authenticationScheme }, - { "Caption", "Windows:" + authenticationScheme }, + { "DisplayName", "Windows:" + authenticationScheme }, }; } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index d8a2fa3e66..b2ab2bfa3f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -202,7 +202,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(1, resultList.Count()); var result = resultList.First(); Assert.Equal(authType.ToString(), result.AuthenticationScheme); - Assert.Equal("Windows:" + authType.ToString(), result.Caption); + Assert.Equal("Windows:" + authType.ToString(), result.DisplayName); } return Task.FromResult(0); From 45cda774bbd57a845dafc40be160961e716c31ef Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Wed, 23 Sep 2015 14:52:50 -0700 Subject: [PATCH 250/597] Enabling NuGetPackageVerifier --- NuGetPackageVerifier.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 NuGetPackageVerifier.json diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json new file mode 100644 index 0000000000..709de17154 --- /dev/null +++ b/NuGetPackageVerifier.json @@ -0,0 +1,27 @@ +{ + "adx": { // Packages written by the ADX team and that ship on NuGet.org + "rules": [ + "AssemblyHasDocumentFileRule", + "AssemblyHasVersionAttributesRule", + "AssemblyHasServicingAttributeRule", + "AssemblyHasNeutralResourcesLanguageAttributeRule", + "SatellitePackageRule", + "StrictSemanticVersionValidationRule" + ], + "packages": { + "Microsoft.AspNet.Server.WebListener": { }, + "Microsoft.Net.Http.Server": { }, + "Microsoft.Net.WebSockets": { } + } + }, + "Default": { // Ru les to run for packages not listed in any other set. + "rules": [ + "AssemblyHasDocumentFileRule", + "AssemblyHasVersionAttributesRule", + "AssemblyHasServicingAttributeRule", + "AssemblyHasNeutralResourcesLanguageAttributeRule", + "SatellitePackageRule", + "StrictSemanticVersionValidationRule" + ] + } +} \ No newline at end of file From d5c0ff8c4a7cc712a7a220ab0914d8d82a47d331 Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Fri, 25 Sep 2015 09:56:18 -0700 Subject: [PATCH 251/597] downgrade System.Threading.Overlapped to fix build --- src/Microsoft.Net.Http.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index ac42adf57d..61f5616c25 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -20,7 +20,7 @@ "System.Security.Claims": "4.0.1-beta-*", "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", "System.Security.Principal.Windows": "4.0.0-beta-*", - "System.Threading.Overlapped": "4.0.1-beta-*" + "System.Threading.Overlapped": "4.0.0" } } } From f6acb01a36a99ffa0abd289b3bf188d8443dfcd4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 28 Sep 2015 23:12:49 -0700 Subject: [PATCH 252/597] Updating to release NuGet.config. --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 1707938c61..9db87a421e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file From 11c31275af562b263f475615a1f260d844a1cc2c Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 30 Sep 2015 15:27:53 -0700 Subject: [PATCH 253/597] React to IFeatureCollection changes. --- .../StandardFeatureCollection.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs index a8b735accb..f3f302a6b2 100644 --- a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs @@ -96,10 +96,5 @@ namespace Microsoft.AspNet.Server.WebListener } } } - - void IDisposable.Dispose() - { - // nothing to dispose of - } } } From 56c80aa7e24ebde189d1bcd5cc665ed050bc4e6c Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 1 Oct 2015 11:58:09 -0700 Subject: [PATCH 254/597] Update 'build.cmd' alias parameter to use full name. --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index 177997c42e..70d974a61f 100644 --- a/build.cmd +++ b/build.cmd @@ -30,7 +30,7 @@ IF "%SKIP_DNX_INSTALL%"=="1" goto run IF %BUILDCMD_DNX_VERSION%=="" ( CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 ) ELSE ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -a default + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -alias default ) CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 From 4400ab4124ccf898ec0aa6ac11d7409bfa08af2f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Sat, 3 Oct 2015 15:44:44 -0700 Subject: [PATCH 255/597] Renaming Microsoft.Framework.* -> Microsoft.Extensions.* --- samples/HotAddSample/Startup.cs | 4 ++-- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/Startup.cs | 2 +- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/LogHelper.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/MessagePump.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs | 4 ++-- src/Microsoft.Net.Http.Server/AuthenticationManager.cs | 4 ++-- src/Microsoft.Net.Http.Server/LogHelper.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 4 ++-- .../RequestProcessing/HeaderCollection.cs | 4 ++-- .../RequestProcessing/HeaderParser.cs | 4 ++-- src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestContext.cs | 2 +- .../RequestProcessing/RequestHeaders.Generated.cs | 2 +- .../RequestProcessing/RequestHeaders.Generated.tt | 4 ++-- .../RequestProcessing/RequestHeaders.cs | 2 +- src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs | 6 +++--- src/Microsoft.Net.Http.Server/WebListener.cs | 4 ++-- src/Microsoft.Net.Http.Server/project.json | 4 ++-- .../RequestHeaderTests.cs | 2 +- .../RequestHeaderTests.cs | 4 ++-- 23 files changed, 35 insertions(+), 35 deletions(-) diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index e5026e9db9..c3e618e1df 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -1,9 +1,9 @@ -using System; +using System; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Features; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Logging; namespace HotAddSample { diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 35533a5c39..ade404891b 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -2,7 +2,7 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNet.Server.WebListener": "1.0.0-*", - "Microsoft.Framework.Logging.Console": "1.0.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "commands": { "web": "Microsoft.AspNet.Server.WebListener --server.urls http://localhost:12345" diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index f7d41f42e5..1af91636e5 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -5,7 +5,7 @@ using System.Threading; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; namespace SelfHostServer diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index cf63300858..ec72077179 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,7 @@ { "dependencies": { "Microsoft.AspNet.Server.WebListener": "1.0.0-*", - "Microsoft.Framework.Logging.Console": "1.0.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "commands": { "web": "Microsoft.AspNet.Server.WebListener --server.urls http://localhost:8080" }, "frameworks": { diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index f40812631f..a9696e1311 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -26,7 +26,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Server; using Microsoft.Net.WebSockets; diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs index c742caa87d..727c2871f6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -24,7 +24,7 @@ using System; using System.Diagnostics; using System.Globalization; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Logging; namespace Microsoft.AspNet.Server.WebListener { diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index 038f54176c..712fab8878 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -20,7 +20,7 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 238c268df7..7600059041 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -41,8 +41,8 @@ using System.Threading.Tasks; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Features; -using Microsoft.Framework.Configuration; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 321851995f..6a8d4f66c4 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Principal; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index a42ae0b0f3..cce8320132 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -23,7 +23,7 @@ using System; using System.Diagnostics; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index c4464119a8..d6dcb837d3 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs index 2190b3dd2f..23778ddec5 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections; using System.Collections.Generic; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs index d4694415d6..8f82c75178 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs @@ -1,9 +1,9 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 2043da2957..87186a1ef0 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -33,7 +33,7 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 905fe8db18..4c0b0a0c14 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -30,7 +30,7 @@ using System.Runtime.InteropServices; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Logging; using Microsoft.Net.WebSockets; namespace Microsoft.Net.Http.Server diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs index 1326e7204d..695f07dd80 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs @@ -29,7 +29,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt index a029f29b02..3f345fcfbe 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt @@ -1,4 +1,4 @@ -<#@ template language="C#" #> +<#@ template language="C#" #> <#@ assembly name="System.Core.dll" #> <#@ import namespace="System.Linq" #> <# @@ -68,7 +68,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs index cc00e29da1..d35e06cc56 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs @@ -39,7 +39,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 8648b3bce5..a23db82eaf 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,8 +32,8 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.Framework.Logging; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; namespace Microsoft.Net.Http.Server diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index c0e4d0676b..29ecb64eba 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; using System.Threading; using System.Threading.Tasks; -using Microsoft.Framework.Logging; +using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 61f5616c25..acd00516e8 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -2,8 +2,8 @@ "version": "1.0.0-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { - "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", - "Microsoft.Framework.Primitives": "1.0.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", + "Microsoft.Extensions.Primitives": "1.0.0-*", "Microsoft.Net.WebSockets": "1.0.0-*" }, "compilationOptions": { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index c8e1302986..d05ca0b4db 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -22,7 +22,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index dd47057415..54ad7c54eb 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Linq; @@ -6,7 +6,7 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; -using Microsoft.Framework.Primitives; +using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.Net.Http.Server From cecd42dfcd624c322be43e4158163b5ac3ec4541 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 7 Oct 2015 13:02:48 -0700 Subject: [PATCH 256/597] React to hosting FeatureCollection change. --- src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index a9696e1311..2213805ad4 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -77,7 +77,7 @@ namespace Microsoft.AspNet.Server.WebListener internal FeatureContext(RequestContext requestContext, bool enableResponseCaching) { _requestContext = requestContext; - _features = new StandardFeatureCollection(this); + _features = new FeatureCollection(new StandardFeatureCollection(this)); _authHandler = new AuthenticationHandler(requestContext); _enableResponseCaching = enableResponseCaching; requestContext.Response.OnStarting(OnStartDelegate, this); From 1befc3b39df886cd96d0f70ab44a07aea54ff34b Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 8 Oct 2015 10:20:57 -0700 Subject: [PATCH 257/597] React to IHeaderDictionary changes. --- .../FeatureContext.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index 2213805ad4..dbf84e121d 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -24,12 +24,13 @@ using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.AspNet.Http.Internal; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Server; -using Microsoft.Net.WebSockets; namespace Microsoft.AspNet.Server.WebListener { @@ -54,7 +55,7 @@ namespace Microsoft.AspNet.Server.WebListener private bool _enableResponseCaching; private Stream _requestBody; - private IDictionary _requestHeaders; + private IHeaderDictionary _requestHeaders; private string _scheme; private string _httpMethod; private string _httpProtocolVersion; @@ -72,7 +73,7 @@ namespace Microsoft.AspNet.Server.WebListener private IAuthenticationHandler _authHandler; private CancellationToken? _disconnectToken; private Stream _responseStream; - private IDictionary _responseHeaders; + private IHeaderDictionary _responseHeaders; internal FeatureContext(RequestContext requestContext, bool enableResponseCaching) { @@ -116,13 +117,13 @@ namespace Microsoft.AspNet.Server.WebListener set { _requestBody = value; } } - IDictionary IHttpRequestFeature.Headers + IHeaderDictionary IHttpRequestFeature.Headers { get { if (_requestHeaders == null) { - _requestHeaders = Request.Headers; + _requestHeaders = new HeaderDictionary(Request.Headers); } return _requestHeaders; } @@ -349,13 +350,13 @@ namespace Microsoft.AspNet.Server.WebListener set { _responseStream = value; } } - IDictionary IHttpResponseFeature.Headers + IHeaderDictionary IHttpResponseFeature.Headers { get { if (_responseHeaders == null) { - _responseHeaders = Response.Headers; + _responseHeaders = new HeaderDictionary(Response.Headers); } return _responseHeaders; } From c4dd09fcedff16c0e2d38f8a8cabc1ed68f4704d Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 8 Oct 2015 19:01:14 -0700 Subject: [PATCH 258/597] React to aspnet/Universe#290 fix --- build.cmd | 25 +++++++++++++------------ build.sh | 12 +++++++----- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/build.cmd b/build.cmd index 70d974a61f..84dc87e480 100644 --- a/build.cmd +++ b/build.cmd @@ -18,22 +18,23 @@ md .nuget copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore -IF EXIST packages\KoreBuild goto run +IF EXIST packages\Sake goto getdnx IF %BUILDCMD_KOREBUILD_VERSION%=="" ( - .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre ) ELSE ( - .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre + .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre ) -.nuget\nuget.exe install Sake -ExcludeVersion -Out packages +.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages -IF "%SKIP_DNX_INSTALL%"=="1" goto run -IF %BUILDCMD_DNX_VERSION%=="" ( - CALL packages\KoreBuild\build\dnvm upgrade -runtime CLR -arch x86 +:getdnx +IF "%SKIP_DNX_INSTALL%"=="" ( + IF "%BUILDCMD_DNX_VERSION%"=="" ( + BUILDCMD_DNX_VERSION=latest + ) + CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default + CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default ) ELSE ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CLR -arch x86 -alias default + CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 ) -CALL packages\KoreBuild\build\dnvm install default -runtime CoreCLR -arch x86 -:run -CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* \ No newline at end of file +packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* diff --git a/build.sh b/build.sh index 0c66139817..da4e3fcd1c 100755 --- a/build.sh +++ b/build.sh @@ -24,18 +24,20 @@ if test ! -e .nuget; then cp $cachePath .nuget/nuget.exe fi -if test ! -d packages/KoreBuild; then +if test ! -d packages/Sake; then mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Out packages + mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages fi if ! type dnvm > /dev/null 2>&1; then source packages/KoreBuild/build/dnvm.sh fi -if ! type dnx > /dev/null 2>&1; then - dnvm upgrade +if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then + dnvm install latest -runtime coreclr -alias default + dnvm install default -runtime mono -alias default +else + dnvm use default -runtime mono fi mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" - From 97eccea8c1e71c1caceb6399818318c2c89b2793 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Mon, 12 Oct 2015 13:06:05 -0700 Subject: [PATCH 259/597] Fix local build break --- build.cmd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.cmd b/build.cmd index 84dc87e480..553e3929a0 100644 --- a/build.cmd +++ b/build.cmd @@ -4,8 +4,8 @@ cd %~dp0 SETLOCAL SET NUGET_VERSION=latest SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe -SET BUILDCMD_KOREBUILD_VERSION="" -SET BUILDCMD_DNX_VERSION="" +SET BUILDCMD_KOREBUILD_VERSION= +SET BUILDCMD_DNX_VERSION= IF EXIST %CACHED_NUGET% goto copynuget echo Downloading latest version of NuGet.exe... @@ -19,7 +19,7 @@ copy %CACHED_NUGET% .nuget\nuget.exe > nul :restore IF EXIST packages\Sake goto getdnx -IF %BUILDCMD_KOREBUILD_VERSION%=="" ( +IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre ) ELSE ( .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre @@ -27,10 +27,10 @@ IF %BUILDCMD_KOREBUILD_VERSION%=="" ( .nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages :getdnx +IF "%BUILDCMD_DNX_VERSION%"=="" ( + SET BUILDCMD_DNX_VERSION=latest +) IF "%SKIP_DNX_INSTALL%"=="" ( - IF "%BUILDCMD_DNX_VERSION%"=="" ( - BUILDCMD_DNX_VERSION=latest - ) CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default ) ELSE ( From 7d132dd87a2f9bde2fad9485d85cb7470d56b194 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 13 Oct 2015 05:20:07 -0700 Subject: [PATCH 260/597] Reacting to testing changes --- WebListener.sln | 44 ++++++++++++++++++- global.json | 2 +- .../OpaqueUpgradeTests.cs | 10 ++--- .../WebSocketTests.cs | 10 ++--- .../OpaqueUpgradeTests.cs | 8 ++-- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/WebListener.sln b/WebListener.sln index 9f9ffbfbf5..77b27f9fbf 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22710.0 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -32,6 +32,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HotAddSample", "samples\HotAddSample\HotAddSample.xproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Testing", "..\testing\src\Microsoft.AspNet.Testing\Microsoft.AspNet.Testing.xproj", "{09BE5203-8042-4338-9713-E44169342E72}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Dnx.TestHost", "..\testing\src\Microsoft.Dnx.TestHost\Microsoft.Dnx.TestHost.xproj", "{F003F228-2AE2-4E9D-877B-93EB773B5061}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Dnx.Testing.Abstractions", "..\testing\src\Microsoft.Dnx.Testing.Abstractions\Microsoft.Dnx.Testing.Abstractions.xproj", "{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -134,6 +140,42 @@ Global {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|x86.ActiveCfg = Release|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|x86.Build.0 = Release|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Debug|x86.ActiveCfg = Debug|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Debug|x86.Build.0 = Debug|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Release|Any CPU.Build.0 = Release|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Release|x86.ActiveCfg = Release|Any CPU + {09BE5203-8042-4338-9713-E44169342E72}.Release|x86.Build.0 = Release|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|x86.ActiveCfg = Debug|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|x86.Build.0 = Debug|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|Any CPU.Build.0 = Release|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|x86.ActiveCfg = Release|Any CPU + {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|x86.Build.0 = Release|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|x86.ActiveCfg = Debug|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|x86.Build.0 = Debug|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|Any CPU.Build.0 = Release|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|x86.ActiveCfg = Release|Any CPU + {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/global.json b/global.json index 983ba0401e..42a9fa1e7a 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,3 @@ { - "projects": ["src"] + "projects": ["src","c:/github/testing/src"] } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index acdb509cad..5b72b73549 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -33,7 +33,7 @@ namespace Microsoft.AspNet.Server.WebListener public class OpaqueUpgradeTests { [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_SupportKeys_Present() { string address; @@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_AfterHeadersSent_Throws() { bool? upgradeThrew = null; @@ -92,7 +92,7 @@ namespace Microsoft.AspNet.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_GetUpgrade_Success() { ManualResetEvent waitHandle = new ManualResetEvent(false); @@ -120,7 +120,7 @@ namespace Microsoft.AspNet.Server.WebListener } [ConditionalTheory] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] // See HTTP_VERB for known verbs [InlineData("UNKNOWN", null)] [InlineData("INVALID", null)] @@ -179,7 +179,7 @@ namespace Microsoft.AspNet.Server.WebListener } [ConditionalTheory] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] // Http.Sys returns a 411 Length Required if PUT or POST does not specify content-length or chunked. [InlineData("POST", "Content-Length: 10")] [InlineData("POST", "Transfer-Encoding: chunked")] diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index 09830bf3f3..c099e3a7d7 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Server.WebListener public class WebSocketTests { [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketTests_SupportKeys_Present() { string address; @@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketTests_AfterHeadersSent_Throws() { bool? upgradeThrew = null; @@ -88,7 +88,7 @@ namespace Microsoft.AspNet.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_Success() { ManualResetEvent waitHandle = new ManualResetEvent(false); @@ -115,7 +115,7 @@ namespace Microsoft.AspNet.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_SendAndReceive_Success() { byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; @@ -161,7 +161,7 @@ namespace Microsoft.AspNet.Server.WebListener return await client.GetAsync(uri); } } - + private async Task SendWebSocketRequestAsync(string address) { ClientWebSocket client = new ClientWebSocket(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index e077352d42..04a17e4241 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -14,7 +14,7 @@ namespace Microsoft.Net.Http.Server public class OpaqueUpgradeTests { [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_AfterHeadersSent_Throws() { string address; @@ -36,7 +36,7 @@ namespace Microsoft.Net.Http.Server } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_GetUpgrade_Success() { string address; @@ -58,7 +58,7 @@ namespace Microsoft.Net.Http.Server } [ConditionalTheory] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] // See HTTP_VERB for known verbs [InlineData("UNKNOWN", null)] [InlineData("INVALID", null)] @@ -114,7 +114,7 @@ namespace Microsoft.Net.Http.Server } [ConditionalTheory] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] // Http.Sys returns a 411 Length Required if PUT or POST does not specify content-length or chunked. [InlineData("POST", "Content-Length: 10")] [InlineData("POST", "Transfer-Encoding: chunked")] From 38b04a0a506079dcb2bbfcd7ed71f9a28b25e986 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 13 Oct 2015 12:02:39 -0700 Subject: [PATCH 261/597] Fix build break --- WebListener.sln | 44 +------------------------------------------- global.json | 2 +- 2 files changed, 2 insertions(+), 44 deletions(-) diff --git a/WebListener.sln b/WebListener.sln index 77b27f9fbf..9f9ffbfbf5 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.22710.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -32,12 +32,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HotAddSample", "samples\HotAddSample\HotAddSample.xproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Testing", "..\testing\src\Microsoft.AspNet.Testing\Microsoft.AspNet.Testing.xproj", "{09BE5203-8042-4338-9713-E44169342E72}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Dnx.TestHost", "..\testing\src\Microsoft.Dnx.TestHost\Microsoft.Dnx.TestHost.xproj", "{F003F228-2AE2-4E9D-877B-93EB773B5061}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Dnx.Testing.Abstractions", "..\testing\src\Microsoft.Dnx.Testing.Abstractions\Microsoft.Dnx.Testing.Abstractions.xproj", "{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -140,42 +134,6 @@ Global {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|x86.ActiveCfg = Release|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|x86.Build.0 = Release|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Debug|Any CPU.Build.0 = Debug|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Debug|x86.ActiveCfg = Debug|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Debug|x86.Build.0 = Debug|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Release|Any CPU.ActiveCfg = Release|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Release|Any CPU.Build.0 = Release|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Release|x86.ActiveCfg = Release|Any CPU - {09BE5203-8042-4338-9713-E44169342E72}.Release|x86.Build.0 = Release|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|x86.ActiveCfg = Debug|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Debug|x86.Build.0 = Debug|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|Any CPU.Build.0 = Release|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|x86.ActiveCfg = Release|Any CPU - {F003F228-2AE2-4E9D-877B-93EB773B5061}.Release|x86.Build.0 = Release|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|x86.ActiveCfg = Debug|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Debug|x86.Build.0 = Debug|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|Any CPU.Build.0 = Release|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|x86.ActiveCfg = Release|Any CPU - {DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/global.json b/global.json index 42a9fa1e7a..983ba0401e 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,3 @@ { - "projects": ["src","c:/github/testing/src"] + "projects": ["src"] } From a494885e3fa4720b61b1b9e2415972594f4ad151 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 13 Oct 2015 12:41:37 -0700 Subject: [PATCH 262/597] React to testing changes --- .../WebSocketTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index 1d600fbd6b..8a9d696905 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -14,7 +14,7 @@ namespace Microsoft.Net.Http.Server public class WebSocketTests { [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_AfterHeadersSent_Throws() { string address; @@ -35,7 +35,7 @@ namespace Microsoft.Net.Http.Server } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_Success() { string address; @@ -53,7 +53,7 @@ namespace Microsoft.Net.Http.Server } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Win7And2008R2)] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_SendAndReceive_Success() { string address; From d2835b6d22cafe3433ca3e1bae00e47dee09f1e5 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 15 Oct 2015 09:35:48 -0700 Subject: [PATCH 263/597] React to Authentication changes. --- .../AuthenticationHandler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs index 242fc3b707..458e5a2009 100644 --- a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs @@ -68,12 +68,12 @@ namespace Microsoft.AspNet.Server.WebListener public Task ChallengeAsync(ChallengeContext context) { - var hasEmptyChallenge = string.IsNullOrEmpty(context.AuthenticationScheme); + var automaticChallenge = string.Equals("Automatic", context.AuthenticationScheme, StringComparison.Ordinal); foreach (var scheme in ListEnabledAuthSchemes()) { var authScheme = scheme.ToString(); // Not including any auth types means it's a blanket challenge for any auth type. - if (hasEmptyChallenge || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) + if (automaticChallenge || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) { switch (context.Behavior) { @@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener case ChallengeBehavior.Automatic: var identity = (ClaimsIdentity)_requestContext.User?.Identity; if (identity != null && identity.IsAuthenticated - && (hasEmptyChallenge || string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal))) + && (automaticChallenge || string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal))) { _requestContext.Response.StatusCode = 403; context.Accept(); From f36faf2a72fce71fcf0a45a741ea551df21477ed Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 21 Oct 2015 10:20:10 -0700 Subject: [PATCH 264/597] React to hosting changes --- src/Microsoft.AspNet.Server.WebListener/Program.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/Program.cs b/src/Microsoft.AspNet.Server.WebListener/Program.cs index ef795cbef0..a13e2ed125 100644 --- a/src/Microsoft.AspNet.Server.WebListener/Program.cs +++ b/src/Microsoft.AspNet.Server.WebListener/Program.cs @@ -28,18 +28,10 @@ namespace Microsoft.AspNet.Server.WebListener { public class Program { - private readonly IServiceProvider _serviceProvider; - - public Program(IServiceProvider serviceProvider) + public static void Main(string[] args) { - _serviceProvider = serviceProvider; - } - - public void Main(string[] args) - { - var program = new Hosting.Program(_serviceProvider); var mergedArgs = new[] { "--server", "Microsoft.AspNet.Server.WebListener" }.Concat(args).ToArray(); - program.Main(mergedArgs); + Hosting.Program.Main(mergedArgs); } } } From 6c467b0475c59be9877e94f59482dffdbc422a02 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 22 Oct 2015 12:34:25 -0700 Subject: [PATCH 265/597] Switch packages to use generation TFMs --- .../project.json | 10 +++- .../NativeInterop/ComNetOS.cs | 4 +- .../NativeInterop/HttpSysSettings.cs | 8 +-- .../NativeInterop/NclUtilities.cs | 4 +- .../NativeInterop/UnsafeNativeMethods.cs | 28 +++++----- .../Overlapped/DeferredDisposableLifetime.cs | 2 +- .../Overlapped/IDeferredDisposable.cs | 2 +- .../Overlapped/PreAllocatedOverlapped.cs | 2 +- .../Overlapped/ThreadPoolBoundHandle.cs | 2 +- .../ThreadPoolBoundHandleOverlapped.cs | 2 +- .../RequestProcessing/OpaqueStream.cs | 6 +- .../RequestProcessing/RequestStream.cs | 10 ++-- .../RequestProcessing/RequestUriBuilder.cs | 4 +- .../RequestProcessing/ResponseStream.cs | 8 +-- .../ResponseStreamAsyncResult.cs | 4 +- .../WebListenerException.cs | 4 +- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 4 +- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 4 +- .../fx/System/Diagnostics/TraceEventType.cs | 4 +- .../fx/System/ExternDll.cs | 4 +- .../InteropServices/ExternalException.cs | 4 +- .../fx/System/SafeNativeMethods.cs | 4 +- src/Microsoft.Net.Http.Server/project.json | 49 ++++++++-------- .../NativeInterop/UnsafeNativeMethods.cs | 10 ++-- src/Microsoft.Net.WebSockets/WebSocketBase.cs | 12 ++-- .../WebSocketException.cs | 4 +- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 4 +- .../fx/System/AccessViolationException.cs | 4 +- .../System/ComponentModel/Win32Exception.cs | 4 +- .../fx/System/ExternDll.cs | 4 +- .../InteropServices/ExternalException.cs | 4 +- .../fx/System/SafeNativeMethods.cs | 4 +- .../fx/System/SystemException.cs | 4 +- src/Microsoft.Net.WebSockets/project.json | 56 +++++++++---------- 34 files changed, 144 insertions(+), 139 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 323f1f29e6..683d0223a1 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -10,11 +10,17 @@ "allowUnsafe": true }, "frameworks": { - "dnx451": { }, + "dnx451": {}, + "net451": { }, "dnxcore50": { "dependencies": { "System.Security.Claims": "4.0.1-beta-*" } + }, + "dotnet5.4": { + "dependencies": { + "System.Security.Claims": "4.0.1-beta-*" + } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index 8a6a9d3b8f..11333417cb 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server static ComNetOS() { -#if DNXCORE50 +#if DOTNET5_4 // TODO: SkipIOCPCallbackOnSuccess doesn't work on Win7. Need a way to detect Win7 vs 8+. IsWin8orLater = false; #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs index 7af55371da..46e3aee54d 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Security; -#if !DNXCORE50 +#if !DOTNET5_4 using Microsoft.Win32; #endif @@ -34,7 +34,7 @@ namespace Microsoft.Net.Http.Server { internal static class HttpSysSettings { -#if !DNXCORE50 +#if !DOTNET5_4 private const string HttpSysParametersKey = @"System\CurrentControlSet\Services\HTTP\Parameters"; #endif private const bool EnableNonUtf8Default = true; @@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server } private static void ReadHttpSysRegistrySettings() -#if DNXCORE50 +#if DOTNET5_4 { } #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs index 5514a946e6..8c939d7bc2 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server get { return Environment.HasShutdownStarted -#if !DNXCORE50 +#if !DOTNET5_4 || AppDomain.CurrentDomain.IsFinalizingForUnload() #endif ; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index d6dcb837d3..e9171f7a8a 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -33,7 +33,7 @@ namespace Microsoft.Net.Http.Server { private const string HTTPAPI = "httpapi.dll"; -#if DNXCORE50 +#if DOTNET5_4 private const string sspicli_LIB = "sspicli.dll"; private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-1.dll"; @@ -63,21 +63,21 @@ namespace Microsoft.Net.Http.Server internal const uint ERROR_CONNECTION_INVALID = 1229; } -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_processthreads_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #endif internal static extern uint GetCurrentThreadId(); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_io_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #endif internal static unsafe extern uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_kernel32_legacy_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] @@ -102,7 +102,7 @@ namespace Microsoft.Net.Http.Server [Out] out HeapAllocHandle resultList); // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366569(v=vs.85).aspx -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_heap_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)] #else [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)] @@ -110,7 +110,7 @@ namespace Microsoft.Net.Http.Server internal static extern IntPtr GetProcessHeap(); // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366701(v=vs.85).aspx -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_heap_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)] #else [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)] @@ -122,7 +122,7 @@ namespace Microsoft.Net.Http.Server internal static class SafeNetHandles { -#if DNXCORE50 +#if DOTNET5_4 [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] @@ -130,7 +130,7 @@ namespace Microsoft.Net.Http.Server internal static extern int FreeContextBuffer( [In] IntPtr contextBuffer); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] @@ -147,21 +147,21 @@ namespace Microsoft.Net.Http.Server [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern bool CloseHandle(IntPtr handle); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_heap_obsolete_LIB, EntryPoint = "LocalAlloc", SetLastError = true)] #else [DllImport(KERNEL32, EntryPoint = "LocalAlloc", SetLastError = true)] @@ -169,21 +169,21 @@ namespace Microsoft.Net.Http.Server internal static extern SafeLocalFreeChannelBinding LocalAllocChannelBinding(int uFlags, UIntPtr sizetdwBytes); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern IntPtr LocalFree(IntPtr handle); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #endif internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] diff --git a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs index 724741009a..80ac921a01 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs @@ -1,4 +1,4 @@ -#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading { diff --git a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs index 7b6395b588..57bf6b41f7 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs @@ -1,4 +1,4 @@ -#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading { diff --git a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs index c4c7b468af..465c816391 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs @@ -1,4 +1,4 @@ -#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading { diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs index 2e3234c206..3b7ad7d966 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs @@ -1,4 +1,4 @@ -#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. using System; using System.Runtime.InteropServices; namespace System.Threading diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs index 7020223dba..753ee35ffd 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs @@ -1,4 +1,4 @@ -#if !DNXCORE50 // TODO: Temp copy. Remove once we target net46. +#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs index 2dd9c0b4ee..4889a8c41b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -109,7 +109,7 @@ namespace Microsoft.Net.Http.Server { return _requestStream.ReadByte(); } -#if !DNXCORE50 +#if !DOTNET5_4 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _requestStream.BeginRead(buffer, offset, count, callback, state); @@ -143,7 +143,7 @@ namespace Microsoft.Net.Http.Server { _responseStream.WriteByte(value); } -#if !DNXCORE50 +#if !DOTNET5_4 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _responseStream.BeginWrite(buffer, offset, count, callback, state); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 3678b298e4..162c8d683e 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -203,7 +203,7 @@ namespace Microsoft.Net.Http.Server } } -#if DNXCORE50 +#if DOTNET5_4 public unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -293,7 +293,7 @@ namespace Microsoft.Net.Http.Server return asyncResult; } -#if DNXCORE50 +#if DOTNET5_4 public int EndRead(IAsyncResult asyncResult) #else public override int EndRead(IAsyncResult asyncResult) @@ -428,7 +428,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if DNXCORE50 +#if DOTNET5_4 public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -437,7 +437,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if DNXCORE50 +#if DOTNET5_4 public void EndWrite(IAsyncResult asyncResult) #else public override void EndWrite(IAsyncResult asyncResult) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 2bd1cf2b6d..971a10bff8 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -70,7 +70,7 @@ namespace Microsoft.Net.Http.Server // TODO: False triggers more detailed/correct parsing, but it's rather slow. UseCookedRequestUrl = true; // SettingsSectionInternal.Section.HttpListenerUnescapeRequestUrl; Utf8Encoding = new UTF8Encoding(false, true); -#if DNXCORE50 +#if DOTNET5_4 AnsiEncoding = Utf8Encoding; #else AnsiEncoding = Encoding.GetEncoding(0, new EncoderExceptionFallback(), new DecoderExceptionFallback()); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 6cc412dba5..579dd1bbe2 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -379,7 +379,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } -#if !DNXCORE50 +#if !DOTNET5_4 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); @@ -468,7 +468,7 @@ namespace Microsoft.Net.Http.Server } } -#if DNXCORE50 +#if DOTNET5_4 public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) #else public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) @@ -476,7 +476,7 @@ namespace Microsoft.Net.Http.Server { return WriteAsync(buffer, offset, count).ToIAsyncResult(callback, state); } -#if DNXCORE50 +#if DOTNET5_4 public void EndWrite(IAsyncResult asyncResult) #else public override void EndWrite(IAsyncResult asyncResult) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 3510080030..43e9b6c027 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -120,7 +120,7 @@ namespace Microsoft.Net.Http.Server var boundHandle = responseStream.RequestContext.Server.BoundHandle; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. -#if DNXCORE50 +#if DOTNET5_4 _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. #else // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. diff --git a/src/Microsoft.Net.Http.Server/WebListenerException.cs b/src/Microsoft.Net.Http.Server/WebListenerException.cs index 7ad45db7eb..8920b3fd25 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerException.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,7 +45,7 @@ namespace Microsoft.Net.Http.Server : base(errorCode, message) { } -#if DNXCORE50 +#if DOTNET5_4 public int ErrorCode #else // the base class returns the HResult with this property diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs index 727e8414df..4a310df3bf 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // // ==--== -#if DNXCORE50 +#if DOTNET5_4 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 01654cbb97..650cffcf86 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // // ==--== -#if DNXCORE50 +#if DOTNET5_4 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs index b51311aeca..bb8a238cf1 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DNXCORE50 +#if DOTNET5_4 using System; using System.ComponentModel; diff --git a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs index 5604c4f1fe..0aa12a91e5 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DNXCORE50 +#if DOTNET5_4 namespace System { diff --git a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs index 89d705b071..1d6c825a65 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if DNXCORE50 +#if DOTNET5_4 namespace System.Runtime.InteropServices { diff --git a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs index 265ed0113a..d890c46b3f 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DNXCORE50 +#if DOTNET5_4 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index acd00516e8..143a302dd8 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,27 +1,26 @@ { - "version": "1.0.0-*", - "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", - "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", - "Microsoft.Extensions.Primitives": "1.0.0-*", - "Microsoft.Net.WebSockets": "1.0.0-*" - }, - "compilationOptions": { - "allowUnsafe": true - }, - "frameworks": { - "net451": { }, - "dnx451": { }, - "dnxcore50": { - "dependencies": { - "Microsoft.Win32.Primitives": "4.0.1-beta-*", - "System.Diagnostics.Debug": "4.0.11-beta-*", - "System.IO.FileSystem": "4.0.1-beta-*", - "System.Security.Claims": "4.0.1-beta-*", - "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", - "System.Security.Principal.Windows": "4.0.0-beta-*", - "System.Threading.Overlapped": "4.0.0" - } - } + "version": "1.0.0-*", + "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", + "Microsoft.Extensions.Primitives": "1.0.0-*", + "Microsoft.Net.WebSockets": "1.0.0-*" + }, + "compilationOptions": { + "allowUnsafe": true + }, + "frameworks": { + "net451": {}, + "dotnet5.4": { + "dependencies": { + "Microsoft.Win32.Primitives": "4.0.1-beta-*", + "System.Diagnostics.Debug": "4.0.11-beta-*", + "System.IO.FileSystem": "4.0.1-beta-*", + "System.Security.Claims": "4.0.1-beta-*", + "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", + "System.Security.Principal.Windows": "4.0.0-beta-*", + "System.Threading.Overlapped": "4.0.0-beta-*" + } } -} + } +} \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs index c0d176fb5e..8b81c7cd96 100644 --- a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ namespace Microsoft.Net.WebSockets { internal static class UnsafeNativeMethods { -#if DNXCORE50 +#if DOTNET5_4 private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll"; #else private const string KERNEL32 = "kernel32.dll"; @@ -40,14 +40,14 @@ namespace Microsoft.Net.WebSockets internal static class SafeNetHandles { -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CharSet=CharSet.Unicode, SetLastError = true)] #endif internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); -#if DNXCORE50 +#if DOTNET5_4 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] @@ -173,7 +173,7 @@ namespace Microsoft.Net.WebSockets static WebSocketProtocolComponent() { -#if DNXCORE50 +#if DOTNET5_4 DllFileName = Path.Combine(Environment.GetEnvironmentVariable("SYSTEMROOT"), "System32", WEBSOCKET); #else DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); diff --git a/src/Microsoft.Net.WebSockets/WebSocketBase.cs b/src/Microsoft.Net.WebSockets/WebSocketBase.cs index 0d6fa52dba..6629e35271 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketBase.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketBase.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -482,7 +482,7 @@ namespace Microsoft.Net.WebSockets _state = WebSocketState.Aborted; -#if DEBUG && NET45 +#if DEBUG && NET451 string stackTrace = new StackTrace().ToString(); if (_closeStack == null) { @@ -715,7 +715,7 @@ namespace Microsoft.Net.WebSockets _state = WebSocketState.Closed; -#if DEBUG && NET45 +#if DEBUG && NET451 if (_closeStack == null) { _closeStack = new StackTrace().ToString(); @@ -1103,7 +1103,7 @@ namespace Microsoft.Net.WebSockets if (thisLockTaken || sessionHandleLockTaken) { -#if !DNXCORE50 +#if !DOTNET5_4 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -1189,7 +1189,7 @@ namespace Microsoft.Net.WebSockets Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); if (lockTaken) { -#if !DNXCORE50 +#if !DOTNET5_4 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -2253,7 +2253,7 @@ namespace Microsoft.Net.WebSockets "'webSocket.m_KeepAliveTracker' MUST NOT be NULL at this point."); int keepAliveIntervalMilliseconds = (int)_keepAliveInterval.TotalMilliseconds; Contract.Assert(keepAliveIntervalMilliseconds > 0, "'keepAliveIntervalMilliseconds' MUST be POSITIVE."); -#if DNXCORE50 +#if DOTNET5_4 _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); #else if (ExecutionContext.IsFlowSuppressed()) diff --git a/src/Microsoft.Net.WebSockets/WebSocketException.cs b/src/Microsoft.Net.WebSockets/WebSocketException.cs index a8f0b34c45..9724b91448 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketException.cs +++ b/src/Microsoft.Net.WebSockets/WebSocketException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; namespace Microsoft.Net.WebSockets { -#if !DNXCORE50 +#if !DOTNET5_4 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] #endif internal sealed class WebSocketException : Win32Exception diff --git a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 01654cbb97..650cffcf86 100644 --- a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // // ==--== -#if DNXCORE50 +#if DOTNET5_4 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs index 2baee3aab3..b7f6eb4071 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if DNXCORE50 +#if DOTNET5_4 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs index 2ff15c2f89..5c6d0dea8b 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DNXCORE50 +#if DOTNET5_4 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs index 5604c4f1fe..0aa12a91e5 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DNXCORE50 +#if DOTNET5_4 namespace System { diff --git a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs index 89d705b071..1d6c825a65 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if DNXCORE50 +#if DOTNET5_4 namespace System.Runtime.InteropServices { diff --git a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs index 265ed0113a..d890c46b3f 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DNXCORE50 +#if DOTNET5_4 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs index 4f74937813..023d53ffc9 100644 --- a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs +++ b/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if DNXCORE50 +#if DOTNET5_4 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index 23db5571cb..b25f6378d3 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -1,30 +1,30 @@ { - "version": "1.0.0-*", - "description": "Implementation of WebSocket abstract base class. Used by WebListener.", - "dependencies": { - }, - "compilationOptions": { "allowUnsafe": true }, - "frameworks": { - "net451": { }, - "dnx451": { }, - "dnxcore50": { - "dependencies": { - "System.Collections": "4.0.11-beta-*", - "System.Diagnostics.Contracts": "4.0.1-beta-*", - "System.Diagnostics.Tools": "4.0.1-beta-*", - "System.IO": "4.0.11-beta-*", - "System.Linq": "4.0.1-beta-*", - "System.Net.Primitives": "4.0.11-beta-*", - "System.Net.WebSockets": "4.0.0-beta-*", - "System.Resources.ResourceManager": "4.0.1-beta-*", - "System.Runtime.Extensions": "4.0.11-beta-*", - "System.Security.Cryptography.Algorithms": "4.0.0-beta-*", - "System.Text.Encoding.Extensions": "4.0.11-beta-*", - "System.Threading": "4.0.11-beta-*", - "System.Threading.Tasks": "4.0.11-beta-*", - "System.Threading.Timer": "4.0.1-beta-*", - "System.Threading.ThreadPool": "4.0.10-beta-*" - } - } + "version": "1.0.0-*", + "description": "Implementation of WebSocket abstract base class. Used by WebListener.", + "dependencies": {}, + "compilationOptions": { + "allowUnsafe": true + }, + "frameworks": { + "net451": {}, + "dotnet5.4": { + "dependencies": { + "System.Collections": "4.0.11-beta-*", + "System.Diagnostics.Contracts": "4.0.1-beta-*", + "System.Diagnostics.Tools": "4.0.1-beta-*", + "System.IO": "4.0.11-beta-*", + "System.Linq": "4.0.1-beta-*", + "System.Net.Primitives": "4.0.11-beta-*", + "System.Net.WebSockets": "4.0.0-beta-*", + "System.Resources.ResourceManager": "4.0.1-beta-*", + "System.Runtime.Extensions": "4.0.11-beta-*", + "System.Security.Cryptography.Algorithms": "4.0.0-beta-*", + "System.Text.Encoding.Extensions": "4.0.11-beta-*", + "System.Threading": "4.0.11-beta-*", + "System.Threading.Tasks": "4.0.11-beta-*", + "System.Threading.Timer": "4.0.1-beta-*", + "System.Threading.ThreadPool": "4.0.10-beta-*" + } } -} + } +} \ No newline at end of file From 0a563be9e9b3127f3ddcaa52b689955cef68c647 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 23 Oct 2015 14:46:48 -0700 Subject: [PATCH 266/597] React to breaking changes in StringValues --- .../RequestHeaders.Generated.cs | 494 +++++++++--------- .../RequestHeaders.Generated.tt | 12 +- 2 files changed, 253 insertions(+), 253 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs index 695f07dd80..2989607022 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs @@ -991,199 +991,199 @@ namespace Microsoft.Net.Http.Server case 2: if (string.Equals(key, "Te", StringComparison.OrdinalIgnoreCase)) { - return Te != null; + return Te.Count > 0; } break; case 3: if (string.Equals(key, "Via", StringComparison.OrdinalIgnoreCase)) { - return Via != null; + return Via.Count > 0; } break; case 4: if (string.Equals(key, "Date", StringComparison.OrdinalIgnoreCase)) { - return Date != null; + return Date.Count > 0; } if (string.Equals(key, "From", StringComparison.OrdinalIgnoreCase)) { - return From != null; + return From.Count > 0; } if (string.Equals(key, "Host", StringComparison.OrdinalIgnoreCase)) { - return Host != null; + return Host.Count > 0; } break; case 5: if (string.Equals(key, "Allow", StringComparison.OrdinalIgnoreCase)) { - return Allow != null; + return Allow.Count > 0; } if (string.Equals(key, "Range", StringComparison.OrdinalIgnoreCase)) { - return Range != null; + return Range.Count > 0; } break; case 6: if (string.Equals(key, "Accept", StringComparison.OrdinalIgnoreCase)) { - return Accept != null; + return Accept.Count > 0; } if (string.Equals(key, "Cookie", StringComparison.OrdinalIgnoreCase)) { - return Cookie != null; + return Cookie.Count > 0; } if (string.Equals(key, "Expect", StringComparison.OrdinalIgnoreCase)) { - return Expect != null; + return Expect.Count > 0; } if (string.Equals(key, "Pragma", StringComparison.OrdinalIgnoreCase)) { - return Pragma != null; + return Pragma.Count > 0; } break; case 7: if (string.Equals(key, "Expires", StringComparison.OrdinalIgnoreCase)) { - return Expires != null; + return Expires.Count > 0; } if (string.Equals(key, "Referer", StringComparison.OrdinalIgnoreCase)) { - return Referer != null; + return Referer.Count > 0; } if (string.Equals(key, "Trailer", StringComparison.OrdinalIgnoreCase)) { - return Trailer != null; + return Trailer.Count > 0; } if (string.Equals(key, "Upgrade", StringComparison.OrdinalIgnoreCase)) { - return Upgrade != null; + return Upgrade.Count > 0; } if (string.Equals(key, "Warning", StringComparison.OrdinalIgnoreCase)) { - return Warning != null; + return Warning.Count > 0; } break; case 8: if (string.Equals(key, "If-Match", StringComparison.OrdinalIgnoreCase)) { - return IfMatch != null; + return IfMatch.Count > 0; } if (string.Equals(key, "If-Range", StringComparison.OrdinalIgnoreCase)) { - return IfRange != null; + return IfRange.Count > 0; } break; case 9: if (string.Equals(key, "Translate", StringComparison.OrdinalIgnoreCase)) { - return Translate != null; + return Translate.Count > 0; } break; case 10: if (string.Equals(key, "Connection", StringComparison.OrdinalIgnoreCase)) { - return Connection != null; + return Connection.Count > 0; } if (string.Equals(key, "Keep-Alive", StringComparison.OrdinalIgnoreCase)) { - return KeepAlive != null; + return KeepAlive.Count > 0; } if (string.Equals(key, "User-Agent", StringComparison.OrdinalIgnoreCase)) { - return UserAgent != null; + return UserAgent.Count > 0; } break; case 11: if (string.Equals(key, "Content-Md5", StringComparison.OrdinalIgnoreCase)) { - return ContentMd5 != null; + return ContentMd5.Count > 0; } break; case 12: if (string.Equals(key, "Content-Type", StringComparison.OrdinalIgnoreCase)) { - return ContentType != null; + return ContentType.Count > 0; } if (string.Equals(key, "Max-Forwards", StringComparison.OrdinalIgnoreCase)) { - return MaxForwards != null; + return MaxForwards.Count > 0; } break; case 13: if (string.Equals(key, "Authorization", StringComparison.OrdinalIgnoreCase)) { - return Authorization != null; + return Authorization.Count > 0; } if (string.Equals(key, "Cache-Control", StringComparison.OrdinalIgnoreCase)) { - return CacheControl != null; + return CacheControl.Count > 0; } if (string.Equals(key, "Content-Range", StringComparison.OrdinalIgnoreCase)) { - return ContentRange != null; + return ContentRange.Count > 0; } if (string.Equals(key, "If-None-Match", StringComparison.OrdinalIgnoreCase)) { - return IfNoneMatch != null; + return IfNoneMatch.Count > 0; } if (string.Equals(key, "Last-Modified", StringComparison.OrdinalIgnoreCase)) { - return LastModified != null; + return LastModified.Count > 0; } break; case 14: if (string.Equals(key, "Accept-Charset", StringComparison.OrdinalIgnoreCase)) { - return AcceptCharset != null; + return AcceptCharset.Count > 0; } if (string.Equals(key, "Content-Length", StringComparison.OrdinalIgnoreCase)) { - return ContentLength != null; + return ContentLength.Count > 0; } break; case 15: if (string.Equals(key, "Accept-Encoding", StringComparison.OrdinalIgnoreCase)) { - return AcceptEncoding != null; + return AcceptEncoding.Count > 0; } if (string.Equals(key, "Accept-Language", StringComparison.OrdinalIgnoreCase)) { - return AcceptLanguage != null; + return AcceptLanguage.Count > 0; } break; case 16: if (string.Equals(key, "Content-Encoding", StringComparison.OrdinalIgnoreCase)) { - return ContentEncoding != null; + return ContentEncoding.Count > 0; } if (string.Equals(key, "Content-Language", StringComparison.OrdinalIgnoreCase)) { - return ContentLanguage != null; + return ContentLanguage.Count > 0; } if (string.Equals(key, "Content-Location", StringComparison.OrdinalIgnoreCase)) { - return ContentLocation != null; + return ContentLocation.Count > 0; } break; case 17: if (string.Equals(key, "If-Modified-Since", StringComparison.OrdinalIgnoreCase)) { - return IfModifiedSince != null; + return IfModifiedSince.Count > 0; } if (string.Equals(key, "Transfer-Encoding", StringComparison.OrdinalIgnoreCase)) { - return TransferEncoding != null; + return TransferEncoding.Count > 0; } break; case 19: if (string.Equals(key, "If-Unmodified-Since", StringComparison.OrdinalIgnoreCase)) { - return IfUnmodifiedSince != null; + return IfUnmodifiedSince.Count > 0; } if (string.Equals(key, "Proxy-Authorization", StringComparison.OrdinalIgnoreCase)) { - return ProxyAuthorization != null; + return ProxyAuthorization.Count > 0; } break; } @@ -1198,239 +1198,239 @@ namespace Microsoft.Net.Http.Server if (string.Equals(key, "Te", StringComparison.OrdinalIgnoreCase)) { value = Te; - return value != null; + return value.Count > 0; } break; case 3: if (string.Equals(key, "Via", StringComparison.OrdinalIgnoreCase)) { value = Via; - return value != null; + return value.Count > 0; } break; case 4: if (string.Equals(key, "Date", StringComparison.OrdinalIgnoreCase)) { value = Date; - return value != null; + return value.Count > 0; } if (string.Equals(key, "From", StringComparison.OrdinalIgnoreCase)) { value = From; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Host", StringComparison.OrdinalIgnoreCase)) { value = Host; - return value != null; + return value.Count > 0; } break; case 5: if (string.Equals(key, "Allow", StringComparison.OrdinalIgnoreCase)) { value = Allow; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Range", StringComparison.OrdinalIgnoreCase)) { value = Range; - return value != null; + return value.Count > 0; } break; case 6: if (string.Equals(key, "Accept", StringComparison.OrdinalIgnoreCase)) { value = Accept; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Cookie", StringComparison.OrdinalIgnoreCase)) { value = Cookie; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Expect", StringComparison.OrdinalIgnoreCase)) { value = Expect; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Pragma", StringComparison.OrdinalIgnoreCase)) { value = Pragma; - return value != null; + return value.Count > 0; } break; case 7: if (string.Equals(key, "Expires", StringComparison.OrdinalIgnoreCase)) { value = Expires; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Referer", StringComparison.OrdinalIgnoreCase)) { value = Referer; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Trailer", StringComparison.OrdinalIgnoreCase)) { value = Trailer; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Upgrade", StringComparison.OrdinalIgnoreCase)) { value = Upgrade; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Warning", StringComparison.OrdinalIgnoreCase)) { value = Warning; - return value != null; + return value.Count > 0; } break; case 8: if (string.Equals(key, "If-Match", StringComparison.OrdinalIgnoreCase)) { value = IfMatch; - return value != null; + return value.Count > 0; } if (string.Equals(key, "If-Range", StringComparison.OrdinalIgnoreCase)) { value = IfRange; - return value != null; + return value.Count > 0; } break; case 9: if (string.Equals(key, "Translate", StringComparison.OrdinalIgnoreCase)) { value = Translate; - return value != null; + return value.Count > 0; } break; case 10: if (string.Equals(key, "Connection", StringComparison.OrdinalIgnoreCase)) { value = Connection; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Keep-Alive", StringComparison.OrdinalIgnoreCase)) { value = KeepAlive; - return value != null; + return value.Count > 0; } if (string.Equals(key, "User-Agent", StringComparison.OrdinalIgnoreCase)) { value = UserAgent; - return value != null; + return value.Count > 0; } break; case 11: if (string.Equals(key, "Content-Md5", StringComparison.OrdinalIgnoreCase)) { value = ContentMd5; - return value != null; + return value.Count > 0; } break; case 12: if (string.Equals(key, "Content-Type", StringComparison.OrdinalIgnoreCase)) { value = ContentType; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Max-Forwards", StringComparison.OrdinalIgnoreCase)) { value = MaxForwards; - return value != null; + return value.Count > 0; } break; case 13: if (string.Equals(key, "Authorization", StringComparison.OrdinalIgnoreCase)) { value = Authorization; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Cache-Control", StringComparison.OrdinalIgnoreCase)) { value = CacheControl; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Content-Range", StringComparison.OrdinalIgnoreCase)) { value = ContentRange; - return value != null; + return value.Count > 0; } if (string.Equals(key, "If-None-Match", StringComparison.OrdinalIgnoreCase)) { value = IfNoneMatch; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Last-Modified", StringComparison.OrdinalIgnoreCase)) { value = LastModified; - return value != null; + return value.Count > 0; } break; case 14: if (string.Equals(key, "Accept-Charset", StringComparison.OrdinalIgnoreCase)) { value = AcceptCharset; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Content-Length", StringComparison.OrdinalIgnoreCase)) { value = ContentLength; - return value != null; + return value.Count > 0; } break; case 15: if (string.Equals(key, "Accept-Encoding", StringComparison.OrdinalIgnoreCase)) { value = AcceptEncoding; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Accept-Language", StringComparison.OrdinalIgnoreCase)) { value = AcceptLanguage; - return value != null; + return value.Count > 0; } break; case 16: if (string.Equals(key, "Content-Encoding", StringComparison.OrdinalIgnoreCase)) { value = ContentEncoding; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Content-Language", StringComparison.OrdinalIgnoreCase)) { value = ContentLanguage; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Content-Location", StringComparison.OrdinalIgnoreCase)) { value = ContentLocation; - return value != null; + return value.Count > 0; } break; case 17: if (string.Equals(key, "If-Modified-Since", StringComparison.OrdinalIgnoreCase)) { value = IfModifiedSince; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Transfer-Encoding", StringComparison.OrdinalIgnoreCase)) { value = TransferEncoding; - return value != null; + return value.Count > 0; } break; case 19: if (string.Equals(key, "If-Unmodified-Since", StringComparison.OrdinalIgnoreCase)) { value = IfUnmodifiedSince; - return value != null; + return value.Count > 0; } if (string.Equals(key, "Proxy-Authorization", StringComparison.OrdinalIgnoreCase)) { value = ProxyAuthorization; - return value != null; + return value.Count > 0; } break; } @@ -1731,7 +1731,7 @@ namespace Microsoft.Net.Http.Server switch (key.Length) { case 2: - if (_Te != null + if (_Te.Count > 0 && string.Equals(key, "Te", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x2u) != 0); @@ -1740,8 +1740,8 @@ namespace Microsoft.Net.Http.Server } break; case 3: - if (_Via != null - && string.Equals(key, "Via", StringComparison.Ordinal)) + if (_Via.Count > 0 + && string.Equals(key, "Via", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x80u) != 0); Via = StringValues.Empty; @@ -1749,21 +1749,21 @@ namespace Microsoft.Net.Http.Server } break; case 4: - if (_Date != null + if (_Date.Count > 0 && string.Equals(key, "Date", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10000u) != 0); Date = StringValues.Empty; return wasSet; } - if (_From != null + if (_From.Count > 0 && string.Equals(key, "From", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80000u) != 0); From = StringValues.Empty; return wasSet; } - if (_Host != null + if (_Host.Count > 0 && string.Equals(key, "Host", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x100000u) != 0); @@ -1772,14 +1772,14 @@ namespace Microsoft.Net.Http.Server } break; case 5: - if (_Allow != null + if (_Allow.Count > 0 && string.Equals(key, "Allow", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10u) != 0); Allow = StringValues.Empty; return wasSet; } - if (_Range != null + if (_Range.Count > 0 && string.Equals(key, "Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80000000u) != 0); @@ -1788,28 +1788,28 @@ namespace Microsoft.Net.Http.Server } break; case 6: - if (_Accept != null + if (_Accept.Count > 0 && string.Equals(key, "Accept", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1u) != 0); Accept = StringValues.Empty; return wasSet; } - if (_Cookie != null + if (_Cookie.Count > 0 && string.Equals(key, "Cookie", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8000u) != 0); Cookie = StringValues.Empty; return wasSet; } - if (_Expect != null + if (_Expect.Count > 0 && string.Equals(key, "Expect", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20000u) != 0); Expect = StringValues.Empty; return wasSet; } - if (_Pragma != null + if (_Pragma.Count > 0 && string.Equals(key, "Pragma", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20000000u) != 0); @@ -1818,35 +1818,35 @@ namespace Microsoft.Net.Http.Server } break; case 7: - if (_Expires != null + if (_Expires.Count > 0 && string.Equals(key, "Expires", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40000u) != 0); Expires = StringValues.Empty; return wasSet; } - if (_Referer != null + if (_Referer.Count > 0 && string.Equals(key, "Referer", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x1u) != 0); Referer = StringValues.Empty; return wasSet; } - if (_Trailer != null + if (_Trailer.Count > 0 && string.Equals(key, "Trailer", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x4u) != 0); Trailer = StringValues.Empty; return wasSet; } - if (_Upgrade != null + if (_Upgrade.Count > 0 && string.Equals(key, "Upgrade", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x20u) != 0); Upgrade = StringValues.Empty; return wasSet; } - if (_Warning != null + if (_Warning.Count > 0 && string.Equals(key, "Warning", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x100u) != 0); @@ -1855,14 +1855,14 @@ namespace Microsoft.Net.Http.Server } break; case 8: - if (_IfMatch != null + if (_IfMatch.Count > 0 && string.Equals(key, "If-Match", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x200000u) != 0); IfMatch = StringValues.Empty; return wasSet; } - if (_IfRange != null + if (_IfRange.Count > 0 && string.Equals(key, "If-Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1000000u) != 0); @@ -1871,7 +1871,7 @@ namespace Microsoft.Net.Http.Server } break; case 9: - if (_Translate != null + if (_Translate.Count > 0 && string.Equals(key, "Translate", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x10u) != 0); @@ -1880,21 +1880,21 @@ namespace Microsoft.Net.Http.Server } break; case 10: - if (_Connection != null + if (_Connection.Count > 0 && string.Equals(key, "Connection", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80u) != 0); Connection = StringValues.Empty; return wasSet; } - if (_KeepAlive != null + if (_KeepAlive.Count > 0 && string.Equals(key, "Keep-Alive", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4000000u) != 0); KeepAlive = StringValues.Empty; return wasSet; } - if (_UserAgent != null + if (_UserAgent.Count > 0 && string.Equals(key, "User-Agent", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x40u) != 0); @@ -1903,7 +1903,7 @@ namespace Microsoft.Net.Http.Server } break; case 11: - if (_ContentMd5 != null + if (_ContentMd5.Count > 0 && string.Equals(key, "Content-Md5", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1000u) != 0); @@ -1912,14 +1912,14 @@ namespace Microsoft.Net.Http.Server } break; case 12: - if (_ContentType != null + if (_ContentType.Count > 0 && string.Equals(key, "Content-Type", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4000u) != 0); ContentType = StringValues.Empty; return wasSet; } - if (_MaxForwards != null + if (_MaxForwards.Count > 0 && string.Equals(key, "Max-Forwards", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10000000u) != 0); @@ -1928,35 +1928,35 @@ namespace Microsoft.Net.Http.Server } break; case 13: - if (_Authorization != null + if (_Authorization.Count > 0 && string.Equals(key, "Authorization", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20u) != 0); Authorization = StringValues.Empty; return wasSet; } - if (_CacheControl != null + if (_CacheControl.Count > 0 && string.Equals(key, "Cache-Control", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40u) != 0); CacheControl = StringValues.Empty; return wasSet; } - if (_ContentRange != null + if (_ContentRange.Count > 0 && string.Equals(key, "Content-Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2000u) != 0); ContentRange = StringValues.Empty; return wasSet; } - if (_IfNoneMatch != null + if (_IfNoneMatch.Count > 0 && string.Equals(key, "If-None-Match", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x800000u) != 0); IfNoneMatch = StringValues.Empty; return wasSet; } - if (_LastModified != null + if (_LastModified.Count > 0 && string.Equals(key, "Last-Modified", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8000000u) != 0); @@ -1965,14 +1965,14 @@ namespace Microsoft.Net.Http.Server } break; case 14: - if (_AcceptCharset != null + if (_AcceptCharset.Count > 0 && string.Equals(key, "Accept-Charset", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2u) != 0); AcceptCharset = StringValues.Empty; return wasSet; } - if (_ContentLength != null + if (_ContentLength.Count > 0 && string.Equals(key, "Content-Length", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x400u) != 0); @@ -1981,14 +1981,14 @@ namespace Microsoft.Net.Http.Server } break; case 15: - if (_AcceptEncoding != null + if (_AcceptEncoding.Count > 0 && string.Equals(key, "Accept-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4u) != 0); AcceptEncoding = StringValues.Empty; return wasSet; } - if (_AcceptLanguage != null + if (_AcceptLanguage.Count > 0 && string.Equals(key, "Accept-Language", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8u) != 0); @@ -1997,21 +1997,21 @@ namespace Microsoft.Net.Http.Server } break; case 16: - if (_ContentEncoding != null + if (_ContentEncoding.Count > 0 && string.Equals(key, "Content-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x100u) != 0); ContentEncoding = StringValues.Empty; return wasSet; } - if (_ContentLanguage != null + if (_ContentLanguage.Count > 0 && string.Equals(key, "Content-Language", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x200u) != 0); ContentLanguage = StringValues.Empty; return wasSet; } - if (_ContentLocation != null + if (_ContentLocation.Count > 0 && string.Equals(key, "Content-Location", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x800u) != 0); @@ -2020,14 +2020,14 @@ namespace Microsoft.Net.Http.Server } break; case 17: - if (_IfModifiedSince != null + if (_IfModifiedSince.Count > 0 && string.Equals(key, "If-Modified-Since", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x400000u) != 0); IfModifiedSince = StringValues.Empty; return wasSet; } - if (_TransferEncoding != null + if (_TransferEncoding.Count > 0 && string.Equals(key, "Transfer-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x8u) != 0); @@ -2036,14 +2036,14 @@ namespace Microsoft.Net.Http.Server } break; case 19: - if (_IfUnmodifiedSince != null + if (_IfUnmodifiedSince.Count > 0 && string.Equals(key, "If-Unmodified-Since", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2000000u) != 0); IfUnmodifiedSince = StringValues.Empty; return wasSet; } - if (_ProxyAuthorization != null + if (_ProxyAuthorization.Count > 0 && string.Equals(key, "Proxy-Authorization", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40000000u) != 0); @@ -2057,167 +2057,167 @@ namespace Microsoft.Net.Http.Server private IEnumerable PropertiesKeys() { - if (Accept != null) + if (Accept.Count > 0) { yield return "Accept"; } - if (AcceptCharset != null) + if (AcceptCharset.Count > 0) { yield return "Accept-Charset"; } - if (AcceptEncoding != null) + if (AcceptEncoding.Count > 0) { yield return "Accept-Encoding"; } - if (AcceptLanguage != null) + if (AcceptLanguage.Count > 0) { yield return "Accept-Language"; } - if (Allow != null) + if (Allow.Count > 0) { yield return "Allow"; } - if (Authorization != null) + if (Authorization.Count > 0) { yield return "Authorization"; } - if (CacheControl != null) + if (CacheControl.Count > 0) { yield return "Cache-Control"; } - if (Connection != null) + if (Connection.Count > 0) { yield return "Connection"; } - if (ContentEncoding != null) + if (ContentEncoding.Count > 0) { yield return "Content-Encoding"; } - if (ContentLanguage != null) + if (ContentLanguage.Count > 0) { yield return "Content-Language"; } - if (ContentLength != null) + if (ContentLength.Count > 0) { yield return "Content-Length"; } - if (ContentLocation != null) + if (ContentLocation.Count > 0) { yield return "Content-Location"; } - if (ContentMd5 != null) + if (ContentMd5.Count > 0) { yield return "Content-Md5"; } - if (ContentRange != null) + if (ContentRange.Count > 0) { yield return "Content-Range"; } - if (ContentType != null) + if (ContentType.Count > 0) { yield return "Content-Type"; } - if (Cookie != null) + if (Cookie.Count > 0) { yield return "Cookie"; } - if (Date != null) + if (Date.Count > 0) { yield return "Date"; } - if (Expect != null) + if (Expect.Count > 0) { yield return "Expect"; } - if (Expires != null) + if (Expires.Count > 0) { yield return "Expires"; } - if (From != null) + if (From.Count > 0) { yield return "From"; } - if (Host != null) + if (Host.Count > 0) { yield return "Host"; } - if (IfMatch != null) + if (IfMatch.Count > 0) { yield return "If-Match"; } - if (IfModifiedSince != null) + if (IfModifiedSince.Count > 0) { yield return "If-Modified-Since"; } - if (IfNoneMatch != null) + if (IfNoneMatch.Count > 0) { yield return "If-None-Match"; } - if (IfRange != null) + if (IfRange.Count > 0) { yield return "If-Range"; } - if (IfUnmodifiedSince != null) + if (IfUnmodifiedSince.Count > 0) { yield return "If-Unmodified-Since"; } - if (KeepAlive != null) + if (KeepAlive.Count > 0) { yield return "Keep-Alive"; } - if (LastModified != null) + if (LastModified.Count > 0) { yield return "Last-Modified"; } - if (MaxForwards != null) + if (MaxForwards.Count > 0) { yield return "Max-Forwards"; } - if (Pragma != null) + if (Pragma.Count > 0) { yield return "Pragma"; } - if (ProxyAuthorization != null) + if (ProxyAuthorization.Count > 0) { yield return "Proxy-Authorization"; } - if (Range != null) + if (Range.Count > 0) { yield return "Range"; } - if (Referer != null) + if (Referer.Count > 0) { yield return "Referer"; } - if (Te != null) + if (Te.Count > 0) { yield return "Te"; } - if (Trailer != null) + if (Trailer.Count > 0) { yield return "Trailer"; } - if (TransferEncoding != null) + if (TransferEncoding.Count > 0) { yield return "Transfer-Encoding"; } - if (Translate != null) + if (Translate.Count > 0) { yield return "Translate"; } - if (Upgrade != null) + if (Upgrade.Count > 0) { yield return "Upgrade"; } - if (UserAgent != null) + if (UserAgent.Count > 0) { yield return "User-Agent"; } - if (Via != null) + if (Via.Count > 0) { yield return "Via"; } - if (Warning != null) + if (Warning.Count > 0) { yield return "Warning"; } @@ -2225,167 +2225,167 @@ namespace Microsoft.Net.Http.Server private IEnumerable PropertiesValues() { - if (Accept != null) + if (Accept.Count > 0) { yield return Accept; } - if (AcceptCharset != null) + if (AcceptCharset.Count > 0) { yield return AcceptCharset; } - if (AcceptEncoding != null) + if (AcceptEncoding.Count > 0) { yield return AcceptEncoding; } - if (AcceptLanguage != null) + if (AcceptLanguage.Count > 0) { yield return AcceptLanguage; } - if (Allow != null) + if (Allow.Count > 0) { yield return Allow; } - if (Authorization != null) + if (Authorization.Count > 0) { yield return Authorization; } - if (CacheControl != null) + if (CacheControl.Count > 0) { yield return CacheControl; } - if (Connection != null) + if (Connection.Count > 0) { yield return Connection; } - if (ContentEncoding != null) + if (ContentEncoding.Count > 0) { yield return ContentEncoding; } - if (ContentLanguage != null) + if (ContentLanguage.Count > 0) { yield return ContentLanguage; } - if (ContentLength != null) + if (ContentLength.Count > 0) { yield return ContentLength; } - if (ContentLocation != null) + if (ContentLocation.Count > 0) { yield return ContentLocation; } - if (ContentMd5 != null) + if (ContentMd5.Count > 0) { yield return ContentMd5; } - if (ContentRange != null) + if (ContentRange.Count > 0) { yield return ContentRange; } - if (ContentType != null) + if (ContentType.Count > 0) { yield return ContentType; } - if (Cookie != null) + if (Cookie.Count > 0) { yield return Cookie; } - if (Date != null) + if (Date.Count > 0) { yield return Date; } - if (Expect != null) + if (Expect.Count > 0) { yield return Expect; } - if (Expires != null) + if (Expires.Count > 0) { yield return Expires; } - if (From != null) + if (From.Count > 0) { yield return From; } - if (Host != null) + if (Host.Count > 0) { yield return Host; } - if (IfMatch != null) + if (IfMatch.Count > 0) { yield return IfMatch; } - if (IfModifiedSince != null) + if (IfModifiedSince.Count > 0) { yield return IfModifiedSince; } - if (IfNoneMatch != null) + if (IfNoneMatch.Count > 0) { yield return IfNoneMatch; } - if (IfRange != null) + if (IfRange.Count > 0) { yield return IfRange; } - if (IfUnmodifiedSince != null) + if (IfUnmodifiedSince.Count > 0) { yield return IfUnmodifiedSince; } - if (KeepAlive != null) + if (KeepAlive.Count > 0) { yield return KeepAlive; } - if (LastModified != null) + if (LastModified.Count > 0) { yield return LastModified; } - if (MaxForwards != null) + if (MaxForwards.Count > 0) { yield return MaxForwards; } - if (Pragma != null) + if (Pragma.Count > 0) { yield return Pragma; } - if (ProxyAuthorization != null) + if (ProxyAuthorization.Count > 0) { yield return ProxyAuthorization; } - if (Range != null) + if (Range.Count > 0) { yield return Range; } - if (Referer != null) + if (Referer.Count > 0) { yield return Referer; } - if (Te != null) + if (Te.Count > 0) { yield return Te; } - if (Trailer != null) + if (Trailer.Count > 0) { yield return Trailer; } - if (TransferEncoding != null) + if (TransferEncoding.Count > 0) { yield return TransferEncoding; } - if (Translate != null) + if (Translate.Count > 0) { yield return Translate; } - if (Upgrade != null) + if (Upgrade.Count > 0) { yield return Upgrade; } - if (UserAgent != null) + if (UserAgent.Count > 0) { yield return UserAgent; } - if (Via != null) + if (Via.Count > 0) { yield return Via; } - if (Warning != null) + if (Warning.Count > 0) { yield return Warning; } @@ -2393,167 +2393,167 @@ namespace Microsoft.Net.Http.Server private IEnumerable> PropertiesEnumerable() { - if (Accept != null) + if (Accept.Count > 0) { yield return new KeyValuePair("Accept", Accept); } - if (AcceptCharset != null) + if (AcceptCharset.Count > 0) { yield return new KeyValuePair("Accept-Charset", AcceptCharset); } - if (AcceptEncoding != null) + if (AcceptEncoding.Count > 0) { yield return new KeyValuePair("Accept-Encoding", AcceptEncoding); } - if (AcceptLanguage != null) + if (AcceptLanguage.Count > 0) { yield return new KeyValuePair("Accept-Language", AcceptLanguage); } - if (Allow != null) + if (Allow.Count > 0) { yield return new KeyValuePair("Allow", Allow); } - if (Authorization != null) + if (Authorization.Count > 0) { yield return new KeyValuePair("Authorization", Authorization); } - if (CacheControl != null) + if (CacheControl.Count > 0) { yield return new KeyValuePair("Cache-Control", CacheControl); } - if (Connection != null) + if (Connection.Count > 0) { yield return new KeyValuePair("Connection", Connection); } - if (ContentEncoding != null) + if (ContentEncoding.Count > 0) { yield return new KeyValuePair("Content-Encoding", ContentEncoding); } - if (ContentLanguage != null) + if (ContentLanguage.Count > 0) { yield return new KeyValuePair("Content-Language", ContentLanguage); } - if (ContentLength != null) + if (ContentLength.Count > 0) { yield return new KeyValuePair("Content-Length", ContentLength); } - if (ContentLocation != null) + if (ContentLocation.Count > 0) { yield return new KeyValuePair("Content-Location", ContentLocation); } - if (ContentMd5 != null) + if (ContentMd5.Count > 0) { yield return new KeyValuePair("Content-Md5", ContentMd5); } - if (ContentRange != null) + if (ContentRange.Count > 0) { yield return new KeyValuePair("Content-Range", ContentRange); } - if (ContentType != null) + if (ContentType.Count > 0) { yield return new KeyValuePair("Content-Type", ContentType); } - if (Cookie != null) + if (Cookie.Count > 0) { yield return new KeyValuePair("Cookie", Cookie); } - if (Date != null) + if (Date.Count > 0) { yield return new KeyValuePair("Date", Date); } - if (Expect != null) + if (Expect.Count > 0) { yield return new KeyValuePair("Expect", Expect); } - if (Expires != null) + if (Expires.Count > 0) { yield return new KeyValuePair("Expires", Expires); } - if (From != null) + if (From.Count > 0) { yield return new KeyValuePair("From", From); } - if (Host != null) + if (Host.Count > 0) { yield return new KeyValuePair("Host", Host); } - if (IfMatch != null) + if (IfMatch.Count > 0) { yield return new KeyValuePair("If-Match", IfMatch); } - if (IfModifiedSince != null) + if (IfModifiedSince.Count > 0) { yield return new KeyValuePair("If-Modified-Since", IfModifiedSince); } - if (IfNoneMatch != null) + if (IfNoneMatch.Count > 0) { yield return new KeyValuePair("If-None-Match", IfNoneMatch); } - if (IfRange != null) + if (IfRange.Count > 0) { yield return new KeyValuePair("If-Range", IfRange); } - if (IfUnmodifiedSince != null) + if (IfUnmodifiedSince.Count > 0) { yield return new KeyValuePair("If-Unmodified-Since", IfUnmodifiedSince); } - if (KeepAlive != null) + if (KeepAlive.Count > 0) { yield return new KeyValuePair("Keep-Alive", KeepAlive); } - if (LastModified != null) + if (LastModified.Count > 0) { yield return new KeyValuePair("Last-Modified", LastModified); } - if (MaxForwards != null) + if (MaxForwards.Count > 0) { yield return new KeyValuePair("Max-Forwards", MaxForwards); } - if (Pragma != null) + if (Pragma.Count > 0) { yield return new KeyValuePair("Pragma", Pragma); } - if (ProxyAuthorization != null) + if (ProxyAuthorization.Count > 0) { yield return new KeyValuePair("Proxy-Authorization", ProxyAuthorization); } - if (Range != null) + if (Range.Count > 0) { yield return new KeyValuePair("Range", Range); } - if (Referer != null) + if (Referer.Count > 0) { yield return new KeyValuePair("Referer", Referer); } - if (Te != null) + if (Te.Count > 0) { yield return new KeyValuePair("Te", Te); } - if (Trailer != null) + if (Trailer.Count > 0) { yield return new KeyValuePair("Trailer", Trailer); } - if (TransferEncoding != null) + if (TransferEncoding.Count > 0) { yield return new KeyValuePair("Transfer-Encoding", TransferEncoding); } - if (Translate != null) + if (Translate.Count > 0) { yield return new KeyValuePair("Translate", Translate); } - if (Upgrade != null) + if (Upgrade.Count > 0) { yield return new KeyValuePair("Upgrade", Upgrade); } - if (UserAgent != null) + if (UserAgent.Count > 0) { yield return new KeyValuePair("User-Agent", UserAgent); } - if (Via != null) + if (Via.Count > 0) { yield return new KeyValuePair("Via", Via); } - if (Warning != null) + if (Warning.Count > 0) { yield return new KeyValuePair("Warning", Warning); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt index 3f345fcfbe..e89825808b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt @@ -116,7 +116,7 @@ namespace Microsoft.Net.Http.Server <# foreach(var prop in length) { #> if (string.Equals(key, "<#=prop.Key#>", StringComparison.OrdinalIgnoreCase)) { - return <#=prop.Name#> != null; + return <#=prop.Name#>.Count > 0; } <# } #> break; @@ -135,7 +135,7 @@ namespace Microsoft.Net.Http.Server if (string.Equals(key, "<#=prop.Key#>", StringComparison.OrdinalIgnoreCase)) { value = <#=prop.Name#>; - return value != null; + return value.Count > 0; } <# } #> break; @@ -172,7 +172,7 @@ namespace Microsoft.Net.Http.Server <# foreach(var length in lengths) { #> case <#=length.Key#>: <# foreach(var prop in length) { #> - if (_<#=prop.Name#> != null + if (_<#=prop.Name#>.Count > 0 && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) { bool wasSet = <#=IsRead(prop.Index)#>; @@ -189,7 +189,7 @@ namespace Microsoft.Net.Http.Server private IEnumerable PropertiesKeys() { <# foreach(var prop in props) { #> - if (<#=prop.Name#> != null) + if (<#=prop.Name#>.Count > 0) { yield return "<#=prop.Key#>"; } @@ -199,7 +199,7 @@ namespace Microsoft.Net.Http.Server private IEnumerable PropertiesValues() { <# foreach(var prop in props) { #> - if (<#=prop.Name#> != null) + if (<#=prop.Name#>.Count > 0) { yield return <#=prop.Name#>; } @@ -209,7 +209,7 @@ namespace Microsoft.Net.Http.Server private IEnumerable> PropertiesEnumerable() { <# foreach(var prop in props) { #> - if (<#=prop.Name#> != null) + if (<#=prop.Name#>.Count > 0) { yield return new KeyValuePair("<#=prop.Key#>", <#=prop.Name#>); } From 4fdd98489fdfcff9efa5c93834675eb20590bef9 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 28 Oct 2015 12:43:06 -0700 Subject: [PATCH 267/597] Updating to release NuGet.config. --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 1707938c61..9db87a421e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file From 092f689c6a4dc8f5a1029bb79f236eaa53c61742 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 22 Oct 2015 20:28:36 -0700 Subject: [PATCH 268/597] Reacting to Hosting IServerFactory refactoring --- .../MessagePump.cs | 59 +++++-- .../ServerFactory.cs | 59 +------ .../AuthenticationTests.cs | 160 +++++++++--------- .../HttpsTests.cs | 14 +- .../OpaqueUpgradeTests.cs | 15 +- .../RequestBodyTests.cs | 21 +-- .../RequestHeaderTests.cs | 8 +- .../RequestTests.cs | 31 ++-- .../ResponseBodyTests.cs | 24 +-- .../ResponseCachingTests.cs | 30 ++-- .../ResponseHeaderTests.cs | 25 +-- .../ResponseSendFileTests.cs | 41 ++--- .../ResponseTests.cs | 22 +-- .../ServerTests.cs | 35 ++-- .../Utilities.cs | 37 ++-- .../WebSocketTests.cs | 12 +- 16 files changed, 261 insertions(+), 332 deletions(-) diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index 712fab8878..acc5247da6 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -16,25 +16,28 @@ // permissions and limitations under the License. using System; +using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Server.Features; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - - internal class MessagePump : IDisposable + internal class MessagePump : IServer { private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; private readonly Microsoft.Net.Http.Server.WebListener _listener; private readonly ILogger _logger; + private readonly IHttpContextFactory _httpContextFactory; - private AppFunc _appFunc; + private RequestDelegate _appFunc; private int _maxAccepts; private int _acceptorCounts; @@ -43,14 +46,19 @@ namespace Microsoft.AspNet.Server.WebListener private bool _stopping; private int _outstandingRequests; private ManualResetEvent _shutdownSignal; - - // TODO: private IDictionary _capabilities; - - internal MessagePump(Microsoft.Net.Http.Server.WebListener listener, ILoggerFactory loggerFactory) + + internal MessagePump(Microsoft.Net.Http.Server.WebListener listener, ILoggerFactory loggerFactory, IFeatureCollection features, IHttpContextFactory httpContextFactory) { + if (features == null) + { + throw new ArgumentNullException(nameof(Features)); + } + Contract.Assert(listener != null); _listener = listener; _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); + _httpContextFactory = httpContextFactory; + Features = features; _processRequest = new Action(ProcessRequestAsync); _maxAccepts = DefaultMaxAccepts; @@ -80,8 +88,23 @@ namespace Microsoft.AspNet.Server.WebListener internal bool EnableResponseCaching { get; set; } = true; - internal void Start(AppFunc app) + public IFeatureCollection Features { get; } + + public void Start(RequestDelegate app) { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + var addressesFeature = Features.Get(); + if (addressesFeature == null) + { + throw new InvalidOperationException($"{nameof(IServerAddressesFeature)} is missing."); + } + + ParseAddresses(addressesFeature.Addresses, Listener); + // Can't call Start twice Contract.Assert(_appFunc == null); @@ -159,11 +182,14 @@ namespace Microsoft.AspNet.Server.WebListener SetFatalResponse(requestContext, 503); return; } + + HttpContext httpContext = null; try { Interlocked.Increment(ref _outstandingRequests); FeatureContext featureContext = new FeatureContext(requestContext, EnableResponseCaching); - await _appFunc(featureContext.Features).SupressContext(); + httpContext = _httpContextFactory.Create(featureContext.Features); + await _appFunc(httpContext).SupressContext(); requestContext.Dispose(); } catch (Exception ex) @@ -182,6 +208,10 @@ namespace Microsoft.AspNet.Server.WebListener } finally { + if (httpContext != null) + { + _httpContextFactory.Dispose(httpContext); + } if (Interlocked.Decrement(ref _outstandingRequests) == 0 && _stopping) { _shutdownSignal.Set(); @@ -202,6 +232,15 @@ namespace Microsoft.AspNet.Server.WebListener context.Dispose(); } + private void ParseAddresses(ICollection addresses, Microsoft.Net.Http.Server.WebListener listener) + { + foreach (var value in addresses) + { + listener.UrlPrefixes.Add(UrlPrefix.Create(value)); + } + } + + public void Dispose() { _stopping = true; diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 7600059041..4775cad150 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -35,79 +35,44 @@ // limitations under the License. using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Features; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - /// /// Implements the setup process for this server. /// public class ServerFactory : IServerFactory { private ILoggerFactory _loggerFactory; + private IHttpContextFactory _httpContextFactory; - public ServerFactory(ILoggerFactory loggerFactory) + public ServerFactory(ILoggerFactory loggerFactory, IHttpContextFactory httpContextFactory) { _loggerFactory = loggerFactory; + _httpContextFactory = httpContextFactory; } /// /// Creates a configurable instance of the server. /// - /// + /// + /// The server. Invoke Dispose to shut down. [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] - public IFeatureCollection Initialize(IConfiguration configuration) + public IServer CreateServer(IConfiguration configuration) { Microsoft.Net.Http.Server.WebListener listener = new Microsoft.Net.Http.Server.WebListener(_loggerFactory); var serverFeatures = new FeatureCollection(); serverFeatures.Set(listener); - serverFeatures.Set(new MessagePump(listener, _loggerFactory)); serverFeatures.Set(SplitAddresses(configuration)); - return serverFeatures; - } - /// - /// - /// The per-request application entry point. - /// The value returned - /// The server. Invoke Dispose to shut down. - public IDisposable Start(IFeatureCollection serverFeatures, AppFunc app) - { - if (serverFeatures == null) - { - throw new ArgumentNullException("serverFeatures"); - } - if (app == null) - { - throw new ArgumentNullException("app"); - } - - var messagePump = serverFeatures.Get(); - if (messagePump == null) - { - throw new InvalidOperationException("messagePump"); - } - - var addressesFeature = serverFeatures.Get(); - if (addressesFeature == null) - { - throw new InvalidOperationException("IServerAddressesFeature"); - } - - ParseAddresses(addressesFeature.Addresses, messagePump.Listener); - - messagePump.Start(app); - return messagePump; + return new MessagePump(listener, _loggerFactory, serverFeatures, _httpContextFactory); } private IServerAddressesFeature SplitAddresses(IConfiguration config) @@ -123,13 +88,5 @@ namespace Microsoft.AspNet.Server.WebListener } return addressesFeature; } - - private void ParseAddresses(ICollection addresses, Microsoft.Net.Http.Server.WebListener listener) - { - foreach (var value in addresses) - { - listener.UrlPrefixes.Add(UrlPrefix.Create(value)); - } - } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index b2ab2bfa3f..89dac6caaa 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -40,11 +40,11 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); return Task.FromResult(0); })) { @@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, env => + using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => { throw new NotImplementedException(); })) @@ -81,12 +81,12 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); - context.Response.StatusCode = 401; + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); + httpContext.Response.StatusCode = 401; return Task.FromResult(0); })) { @@ -107,12 +107,12 @@ namespace Microsoft.AspNet.Server.WebListener | AuthenticationSchemes.Basic | AuthenticationSchemes.AllowAnonymous, out address, - env => + httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); - context.Response.StatusCode = 401; + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); + httpContext.Response.StatusCode = 401; return Task.FromResult(0); })) { @@ -132,18 +132,18 @@ namespace Microsoft.AspNet.Server.WebListener { string address; int requestId = 0; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); if (requestId == 0) { - Assert.False(context.User.Identity.IsAuthenticated); - context.Response.StatusCode = 401; + Assert.False(httpContext.User.Identity.IsAuthenticated); + httpContext.Response.StatusCode = 401; } else if (requestId == 1) { - Assert.True(context.User.Identity.IsAuthenticated); + Assert.True(httpContext.User.Identity.IsAuthenticated); } else { @@ -167,11 +167,11 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, env => + using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.True(context.User.Identity.IsAuthenticated); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.True(httpContext.User.Identity.IsAuthenticated); return Task.FromResult(0); })) { @@ -189,10 +189,9 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_GetSingleDescriptions(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - var resultList = context.Authentication.GetAuthenticationSchemes(); + var resultList = httpContext.Authentication.GetAuthenticationSchemes(); if (authType == AuthenticationSchemes.AllowAnonymous) { Assert.Equal(0, resultList.Count()); @@ -223,10 +222,9 @@ namespace Microsoft.AspNet.Server.WebListener | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - var resultList = context.Authentication.GetAuthenticationSchemes(); + var resultList = httpContext.Authentication.GetAuthenticationSchemes(); Assert.Equal(3, resultList.Count()); return Task.FromResult(0); })) @@ -247,14 +245,14 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, async env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, async httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); foreach (var scheme in authTypeList) { - var authResults = await context.Authentication.AuthenticateAsync(scheme); + var authResults = await httpContext.Authentication.AuthenticateAsync(scheme); Assert.Null(authResults); } })) @@ -275,15 +273,15 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType, out address, async env => + using (Utilities.CreateHttpAuthServer(authType, out address, async httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.True(context.User.Identity.IsAuthenticated); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.True(httpContext.User.Identity.IsAuthenticated); var count = 0; foreach (var scheme in authTypeList) { - var authResults = await context.Authentication.AuthenticateAsync(scheme); + var authResults = await httpContext.Authentication.AuthenticateAsync(scheme); if (authResults != null) { count++; @@ -307,12 +305,12 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); - return context.Authentication.ChallengeAsync(); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); + return httpContext.Authentication.ChallengeAsync(); })) { var response = await SendRequestAsync(address); @@ -331,14 +329,14 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, async env => + using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, async httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); foreach (var scheme in authTypeList) { - await context.Authentication.ChallengeAsync(scheme); + await httpContext.Authentication.ChallengeAsync(scheme); } })) { @@ -357,12 +355,12 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); - return context.Authentication.ChallengeAsync(authType.ToString()); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); + return httpContext.Authentication.ChallengeAsync(authType.ToString()); })) { var response = await SendRequestAsync(address); @@ -383,12 +381,12 @@ namespace Microsoft.AspNet.Server.WebListener var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; authTypes = authTypes & ~authType; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, env => + using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); - return Assert.ThrowsAsync(() => context.Authentication.ChallengeAsync(authType.ToString())); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); + return Assert.ThrowsAsync(() => httpContext.Authentication.ChallengeAsync(authType.ToString())); })) { var response = await SendRequestAsync(address); @@ -406,12 +404,12 @@ namespace Microsoft.AspNet.Server.WebListener { string address; var authTypes = AuthenticationSchemes.AllowAnonymous | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authTypes, out address, env => + using (Utilities.CreateHttpAuthServer(authTypes, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.False(context.User.Identity.IsAuthenticated); - return context.Authentication.ForbidAsync(authType.ToString()); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); + return httpContext.Authentication.ForbidAsync(authType.ToString()); })) { var response = await SendRequestAsync(address); @@ -428,12 +426,12 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_ChallengeAuthenticatedAuthType_Forbidden(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, env => + using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.True(context.User.Identity.IsAuthenticated); - return context.Authentication.ChallengeAsync(authType.ToString()); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.True(httpContext.User.Identity.IsAuthenticated); + return httpContext.Authentication.ChallengeAsync(authType.ToString()); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); @@ -451,12 +449,12 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, env => + using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.True(context.User.Identity.IsAuthenticated); - return context.Authentication.ChallengeAsync(); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.True(httpContext.User.Identity.IsAuthenticated); + return httpContext.Authentication.ChallengeAsync(); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); @@ -474,12 +472,12 @@ namespace Microsoft.AspNet.Server.WebListener public async Task AuthTypes_UnathorizedAuthenticatedAuthType_Unauthorized(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, env => + using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => { - var context = new DefaultHttpContext((IFeatureCollection)env); - Assert.NotNull(context.User); - Assert.True(context.User.Identity.IsAuthenticated); - return context.Authentication.ChallengeAsync(authType.ToString(), null, ChallengeBehavior.Unauthorized); + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.True(httpContext.User.Identity.IsAuthenticated); + return httpContext.Authentication.ChallengeAsync(authType.ToString(), null, ChallengeBehavior.Unauthorized); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 4ac233d4a4..8a4595705d 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Server.WebListener [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_200OK_Success() { - using (Utilities.CreateHttpsServer(env => + using (Utilities.CreateHttpsServer(httpContext => { return Task.FromResult(0); })) @@ -47,9 +47,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_SendHelloWorld_Success() { - using (Utilities.CreateHttpsServer(env => + using (Utilities.CreateHttpsServer(httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] body = Encoding.UTF8.GetBytes("Hello World"); httpContext.Response.ContentLength = body.Length; return httpContext.Response.Body.WriteAsync(body, 0, body.Length); @@ -63,9 +62,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_EchoHelloWorld_Success() { - using (Utilities.CreateHttpsServer(env => + using (Utilities.CreateHttpsServer(httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); string input = new StreamReader(httpContext.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); byte[] body = Encoding.UTF8.GetBytes("Hello World"); @@ -82,9 +80,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { - using (Utilities.CreateHttpsServer(async env => + using (Utilities.CreateHttpsServer(async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var tls = httpContext.Features.Get(); Assert.NotNull(tls); var cert = await tls.GetClientCertificateAsync(CancellationToken.None); @@ -100,9 +97,8 @@ namespace Microsoft.AspNet.Server.WebListener [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertRequested_ClientCertPresent() { - using (Utilities.CreateHttpsServer(async env => + using (Utilities.CreateHttpsServer(async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var tls = httpContext.Features.Get(); Assert.NotNull(tls); var cert = await tls.GetClientCertificateAsync(CancellationToken.None); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 5b72b73549..4949bd10bb 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -37,9 +37,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task OpaqueUpgrade_SupportKeys_Present() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { var opaqueFeature = httpContext.Features.Get(); @@ -66,9 +65,8 @@ namespace Microsoft.AspNet.Server.WebListener { bool? upgradeThrew = null; string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); await httpContext.Response.WriteAsync("Hello World"); await httpContext.Response.Body.FlushAsync(); try @@ -98,9 +96,8 @@ namespace Microsoft.AspNet.Server.WebListener ManualResetEvent waitHandle = new ManualResetEvent(false); bool? upgraded = null; string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets var opaqueFeature = httpContext.Features.Get(); Assert.NotNull(opaqueFeature); @@ -146,9 +143,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task OpaqueUpgrade_VariousMethodsUpgradeSendAndReceive_Success(string method, string extraHeader) { string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets @@ -190,9 +186,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task OpaqueUpgrade_InvalidMethodUpgrade_Disconnected(string method, string extraHeader) { string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { var opaqueFeature = httpContext.Features.Get(); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index c5edcdf539..b17639491e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -35,9 +35,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestBody_ReadSync_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; int read = httpContext.Request.Body.Read(input, 0, input.Length); httpContext.Response.ContentLength = read; @@ -54,9 +53,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestBody_ReadAync_Success() { string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); httpContext.Response.ContentLength = read; @@ -72,9 +70,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestBody_ReadBeginEnd_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; int read = httpContext.Request.Body.EndRead(httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); httpContext.Response.ContentLength = read; @@ -92,9 +89,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestBody_InvalidBuffer_ArgumentException() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[100]; Assert.Throws("buffer", () => httpContext.Request.Body.Read(null, 0, 1)); Assert.Throws("offset", () => httpContext.Request.Body.Read(input, -1, 1)); @@ -116,9 +112,8 @@ namespace Microsoft.AspNet.Server.WebListener { StaggardContent content = new StaggardContent(); string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[10]; int read = httpContext.Request.Body.Read(input, 0, input.Length); Assert.Equal(5, read); @@ -138,9 +133,8 @@ namespace Microsoft.AspNet.Server.WebListener { StaggardContent content = new StaggardContent(); string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[10]; int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(5, read); @@ -158,9 +152,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestBody_PostWithImidateBody_Success() { string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); byte[] input = new byte[11]; int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(10, read); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index d05ca0b4db..f4fd3c378c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -33,9 +33,9 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestHeaders_ClientSendsDefaultHeaders_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; + var requestHeaders = httpContext.Request.Headers; // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. // Assert.Equal(2, requestHeaders.Count); // Assert.Equal("Keep-Alive", requestHeaders.Get("Connection")); @@ -53,9 +53,9 @@ namespace Microsoft.AspNet.Server.WebListener public async Task RequestHeaders_ClientSendsCustomHeaders_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var requestHeaders = new DefaultHttpContext((IFeatureCollection)env).Request.Headers; + var requestHeaders = httpContext.Request.Headers; Assert.Equal(4, requestHeaders.Count); Assert.False(StringValues.IsNullOrEmpty(requestHeaders["Host"])); Assert.Equal("close", requestHeaders["Connection"]); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 0ebbfb6c00..424f536847 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -20,6 +20,9 @@ using System.IO; using System.Net.Http; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Builder; +using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Microsoft.Net.Http.Server; @@ -27,17 +30,14 @@ using Xunit; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - public class RequestTests { [Fact] public async Task Request_SimpleGet_Success() { string root; - using (Utilities.CreateHttpServerReturnRoot("/basepath", out root, env => + using (Utilities.CreateHttpServerReturnRoot("/basepath", out root, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { var requestInfo = httpContext.Features.Get(); @@ -53,7 +53,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal("HTTP/1.1", requestInfo.Protocol); // Server Keys - // TODO: Assert.NotNull(env.Get>("server.Capabilities")); + // TODO: Assert.NotNull(httpContext.Get>("server.Capabilities")); var connectionInfo = httpContext.Features.Get(); Assert.Equal("::1", connectionInfo.RemoteIpAddress.ToString()); @@ -92,9 +92,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Request_PathSplitting(string pathBase, string requestPath, string expectedPathBase, string expectedPath) { string root; - using (Utilities.CreateHttpServerReturnRoot(pathBase, out root, env => + using (Utilities.CreateHttpServerReturnRoot(pathBase, out root, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { var requestInfo = httpContext.Features.Get(); @@ -140,9 +139,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Request_MultiplePrefixes(string requestPath, string expectedPathBase, string expectedPath) { string root; - using (CreateServer(out root, env => + using (CreateServer(out root, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var requestInfo = httpContext.Features.Get(); var requestIdentifierFeature = httpContext.Features.Get(); try @@ -167,22 +165,23 @@ namespace Microsoft.AspNet.Server.WebListener } } - private IDisposable CreateServer(out string root, AppFunc app) + private IServer CreateServer(out string root, RequestDelegate app) { // TODO: We're just doing this to get a dynamic port. This can be removed later when we add support for hot-adding prefixes. - var server = Utilities.CreateHttpServerReturnRoot("/", out root, app); - server.Dispose(); + var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app); + dynamicServer.Dispose(); var rootUri = new Uri(root); - var factory = new ServerFactory(loggerFactory: null); - var serverFeatures = factory.Initialize(configuration: null); - var listener = serverFeatures.Get(); + var factory = new ServerFactory(loggerFactory: null, httpContextFactory: new HttpContextFactory(new HttpContextAccessor())); + var server = factory.CreateServer(configuration: null); + var listener = server.Features.Get(); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); } - return factory.Start(serverFeatures, app); + server.Start(app); + return server; } private async Task SendRequestAsync(string uri) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index af31ca78b1..2b5800f205 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -35,9 +35,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseBody_WriteNoHeaders_BuffersAndSetsContentLength() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Body.Write(new byte[10], 0, 10); return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) @@ -56,9 +55,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseBody_WriteNoHeadersAndFlush_DefaultsToChunked() { string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Body.Write(new byte[10], 0, 10); await httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); await httpContext.Response.Body.FlushAsync(); @@ -78,9 +76,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseBody_WriteChunked_ManuallyChunked() { string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["transfeR-Encoding"] = " CHunked "; Stream stream = httpContext.Response.Body; var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); @@ -101,9 +98,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseBody_WriteContentLength_PassedThrough() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = httpContext.Response.Body; stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); @@ -126,9 +122,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseBody_WriteContentLengthNoneWritten_Throws() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 20 "; return Task.FromResult(0); })) @@ -141,9 +136,8 @@ namespace Microsoft.AspNet.Server.WebListener public void ResponseBody_WriteContentLengthNotEnoughWritten_Throws() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 20 "; httpContext.Response.Body.Write(new byte[5], 0, 5); return Task.FromResult(0); @@ -157,9 +151,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 10 "; httpContext.Response.Body.Write(new byte[5], 0, 5); httpContext.Response.Body.Write(new byte[6], 0, 6); @@ -177,11 +170,10 @@ namespace Microsoft.AspNet.Server.WebListener ManualResetEvent waitHandle = new ManualResetEvent(false); bool? appThrew = null; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { try { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.Headers["Content-lenGth"] = " 10 "; httpContext.Response.Body.Write(new byte[10], 0, 10); httpContext.Response.Body.Write(new byte[9], 0, 9); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index 6378a7e4f8..0c713606f8 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -17,9 +17,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); @@ -35,9 +34,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; @@ -54,9 +52,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; @@ -73,9 +70,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, s-maxage=10"; @@ -92,9 +88,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=0, s-maxage=10"; @@ -111,9 +106,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; @@ -134,9 +128,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; @@ -156,9 +149,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; @@ -176,9 +168,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Expires"] = (DateTime.UtcNow + TimeSpan.FromSeconds(10)).ToString("r"); @@ -195,9 +186,8 @@ namespace Microsoft.AspNet.Server.WebListener.FunctionalTests { var requestCount = 1; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index f0db3b7557..bd8bb9cf5f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseHeaders_ServerSendsDefaultHeaders_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { return Task.FromResult(0); })) @@ -54,9 +54,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseHeaders_ServerSendsSingleValueKnownHeaders_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["WWW-Authenticate"] = new string[] { "custom1" }; @@ -79,9 +78,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseHeaders_ServerSendsMultiValueKnownHeaders_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["WWW-Authenticate"] = new string[] { "custom1, and custom2", "custom3" }; @@ -104,9 +102,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["Custom-Header1"] = new string[] { "custom1, and custom2", "custom3" }; @@ -129,9 +126,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseHeaders_ServerSendsConnectionClose_Closed() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["Connection"] = new string[] { "Close" }; @@ -154,7 +150,7 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseHeaders_HTTP10Request_Gets11Close() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { return Task.FromResult(0); })) @@ -177,9 +173,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseHeaders_HTTP10RequestWithChunkedHeader_ManualChunking() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["Transfer-Encoding"] = new string[] { "chunked" }; @@ -207,9 +202,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Headers_FlushSendsHeaders_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); @@ -239,9 +233,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Headers_FlushAsyncSendsHeaders_Success() { string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index c52ffc8446..751d4d0e40 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -47,13 +47,12 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_SupportKeys_Present() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { /* TODO: - IDictionary capabilities = env.Get>("server.Capabilities"); + IDictionary capabilities = httpContext.Get>("server.Capabilities"); Assert.NotNull(capabilities); Assert.Equal("1.0", capabilities.Get("sendfile.Version")); @@ -91,9 +90,8 @@ namespace Microsoft.AspNet.Server.WebListener ManualResetEvent waitHandle = new ManualResetEvent(false); bool? appThrew = null; string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); try { @@ -124,9 +122,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) @@ -144,9 +141,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_RelativeFile_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); })) @@ -164,9 +160,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_Unspecified_Chunked() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) @@ -184,9 +179,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_MultipleWrites_Chunked() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None).Wait(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); @@ -205,9 +199,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_HalfOfFile_Chunked() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); })) @@ -225,9 +218,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_OffsetOutOfRange_Throws() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); })) @@ -241,9 +233,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_CountOutOfRange_Throws() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); })) @@ -257,9 +248,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_Count0_Chunked() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) @@ -277,9 +267,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_ContentLength_PassedThrough() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); httpContext.Response.Headers["Content-lenGth"] = FileLength.ToString(); return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); @@ -299,9 +288,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_ContentLengthSpecific_PassedThrough() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); httpContext.Response.Headers["Content-lenGth"] = "10"; return sendFile.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); @@ -321,9 +309,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseSendFile_ContentLength0_PassedThrough() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var sendFile = httpContext.Features.Get(); httpContext.Response.Headers["Content-lenGth"] = "0"; return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs index 40ed9469b0..516b2dc87f 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -31,9 +31,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Response_ServerSendsDefaultResponse_ServerProvidesStatusCodeAndReasonPhrase() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); Assert.Equal(200, httpContext.Response.StatusCode); Assert.False(httpContext.Response.HasStarted); return Task.FromResult(0); @@ -51,11 +50,10 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Response_ServerSendsSpecificStatus_ServerProvidesReasonPhrase() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 201; - // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value + // TODO: httpContext["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value return Task.FromResult(0); })) { @@ -71,12 +69,11 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Response_ServerSendsSpecificStatusAndReasonPhrase_PassedThrough() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 201; httpContext.Features.Get().ReasonPhrase = "CustomReasonPhrase"; // TODO? - // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value + // TODO: httpContext["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value return Task.FromResult(0); })) { @@ -92,9 +89,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Response_ServerSendsCustomStatus_NoReasonPhrase() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 901; return Task.FromResult(0); })) @@ -110,9 +106,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Response_100_Throws() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 100; return Task.FromResult(0); })) @@ -126,9 +121,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Response_0_Throws() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.StatusCode = 0; return Task.FromResult(0); })) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index b787d5e96f..89127762de 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -24,6 +24,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; @@ -38,7 +39,7 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Server_200OK_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { return Task.FromResult(0); })) @@ -52,9 +53,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Server_SendHelloWorld_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentLength = 11; return httpContext.Response.WriteAsync("Hello World"); })) @@ -68,9 +68,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task Server_EchoHelloWorld_Success() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); string input = new StreamReader(httpContext.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); httpContext.Response.ContentLength = 11; @@ -88,10 +87,9 @@ namespace Microsoft.AspNet.Server.WebListener Task responseTask; ManualResetEvent received = new ManualResetEvent(false); string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { received.Set(); - var httpContext = new DefaultHttpContext((IFeatureCollection)env); httpContext.Response.ContentLength = 11; return httpContext.Response.WriteAsync("Hello World"); })) @@ -107,7 +105,7 @@ namespace Microsoft.AspNet.Server.WebListener public void Server_AppException_ClientReset() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { throw new InvalidOperationException(); })) @@ -129,7 +127,7 @@ namespace Microsoft.AspNet.Server.WebListener TaskCompletionSource tcs = new TaskCompletionSource(); string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { if (Interlocked.Increment(ref requestCount) == requestLimit) { @@ -162,7 +160,7 @@ namespace Microsoft.AspNet.Server.WebListener TaskCompletionSource tcs = new TaskCompletionSource(); string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { if (Interlocked.Increment(ref requestCount) == requestLimit) { @@ -193,9 +191,8 @@ namespace Microsoft.AspNet.Server.WebListener ManualResetEvent canceled = new ManualResetEvent(false); string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); CancellationToken ct = httpContext.RequestAborted; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); @@ -228,9 +225,8 @@ namespace Microsoft.AspNet.Server.WebListener ManualResetEvent canceled = new ManualResetEvent(false); string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); CancellationToken ct = httpContext.RequestAborted; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); @@ -255,16 +251,17 @@ namespace Microsoft.AspNet.Server.WebListener { // This is just to get a dynamic port string address; - using (Utilities.CreateHttpServer(out address, env => Task.FromResult(0))) { } + using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } - var factory = new ServerFactory(loggerFactory: null); - var serverFeatures = factory.Initialize(configuration: null); - var listener = serverFeatures.Get(); + var factory = new ServerFactory(loggerFactory: null, httpContextFactory: new HttpContextFactory(new HttpContextAccessor())); + var server = factory.CreateServer(configuration: null); + var listener = server.Features.Get(); listener.UrlPrefixes.Add(UrlPrefix.Create(address)); listener.SetRequestQueueLimit(1001); - using (factory.Start(serverFeatures, env => Task.FromResult(0))) + using (server) { + server.Start(httpContext => Task.FromResult(0)); string response = await SendRequestAsync(address); Assert.Equal(string.Empty, response); } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index 899c18beea..31eb61ea07 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -16,43 +16,44 @@ // permissions and limitations under the License. using System; -using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Server.Features; using Microsoft.Net.Http.Server; namespace Microsoft.AspNet.Server.WebListener { - using AppFunc = Func; - internal static class Utilities { private const int BasePort = 5001; private const int MaxPort = 8000; private static int NextPort = BasePort; private static object PortLock = new object(); + private static IHttpContextFactory Factory = new HttpContextFactory(new HttpContextAccessor()); - internal static IDisposable CreateHttpServer(out string baseAddress, AppFunc app) + internal static IServer CreateHttpServer(out string baseAddress, RequestDelegate app) { string root; return CreateDynamicHttpServer(string.Empty, AuthenticationSchemes.AllowAnonymous, out root, out baseAddress, app); } - internal static IDisposable CreateHttpServerReturnRoot(string path, out string root, AppFunc app) + internal static IServer CreateHttpServerReturnRoot(string path, out string root, RequestDelegate app) { string baseAddress; return CreateDynamicHttpServer(path, AuthenticationSchemes.AllowAnonymous, out root, out baseAddress, app); } - internal static IDisposable CreateHttpAuthServer(AuthenticationSchemes authType, out string baseAddress, AppFunc app) + internal static IServer CreateHttpAuthServer(AuthenticationSchemes authType, out string baseAddress, RequestDelegate app) { string root; return CreateDynamicHttpServer(string.Empty, authType, out root, out baseAddress, app); } - internal static IDisposable CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, out string root, out string baseAddress, AppFunc app) + internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, out string root, out string baseAddress, RequestDelegate app) { - var factory = new ServerFactory(loggerFactory: null); + var factory = new ServerFactory(loggerFactory: null, httpContextFactory: Factory); lock (PortLock) { while (NextPort < MaxPort) @@ -63,13 +64,14 @@ namespace Microsoft.AspNet.Server.WebListener root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; baseAddress = prefix.ToString(); - var serverFeatures = factory.Initialize(configuration: null); - var listener = serverFeatures.Get(); + var server = factory.CreateServer(configuration: null); + var listener = server.Features.Get(); listener.UrlPrefixes.Add(prefix); listener.AuthenticationManager.AuthenticationSchemes = authType; try { - return factory.Start(serverFeatures, app); + server.Start(app); + return server; } catch (WebListenerException) { @@ -80,17 +82,18 @@ namespace Microsoft.AspNet.Server.WebListener throw new Exception("Failed to locate a free port."); } - internal static IDisposable CreateHttpsServer(AppFunc app) + internal static IServer CreateHttpsServer(RequestDelegate app) { return CreateServer("https", "localhost", 9090, string.Empty, app); } - internal static IDisposable CreateServer(string scheme, string host, int port, string path, AppFunc app) + internal static IServer CreateServer(string scheme, string host, int port, string path, RequestDelegate app) { - var factory = new ServerFactory(loggerFactory: null); - var serverFeatures = factory.Initialize(configuration: null); - serverFeatures.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); - return factory.Start(serverFeatures, app); + var factory = new ServerFactory(loggerFactory: null, httpContextFactory: Factory); + var server = factory.CreateServer(configuration: null); + server.Features.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); + server.Start(app); + return server; } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index c099e3a7d7..b6e55b1875 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -35,9 +35,8 @@ namespace Microsoft.AspNet.Server.WebListener public async Task WebSocketTests_SupportKeys_Present() { string address; - using (Utilities.CreateHttpServer(out address, env => + using (Utilities.CreateHttpServer(out address, httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); try { var webSocketFeature = httpContext.Features.Get(); @@ -64,9 +63,8 @@ namespace Microsoft.AspNet.Server.WebListener { bool? upgradeThrew = null; string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); await httpContext.Response.WriteAsync("Hello World"); try { @@ -94,9 +92,8 @@ namespace Microsoft.AspNet.Server.WebListener ManualResetEvent waitHandle = new ManualResetEvent(false); bool? upgraded = null; string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var webSocketFeature = httpContext.Features.Get(); Assert.NotNull(webSocketFeature); Assert.True(webSocketFeature.IsWebSocketRequest); @@ -120,9 +117,8 @@ namespace Microsoft.AspNet.Server.WebListener { byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; string address; - using (Utilities.CreateHttpServer(out address, async env => + using (Utilities.CreateHttpServer(out address, async httpContext => { - var httpContext = new DefaultHttpContext((IFeatureCollection)env); var webSocketFeature = httpContext.Features.Get(); Assert.NotNull(webSocketFeature); Assert.True(webSocketFeature.IsWebSocketRequest); From 8c800fbd0fa54321952f0324f2084cdbdde3dd47 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 2 Nov 2015 14:36:47 -0800 Subject: [PATCH 269/597] Rearranging test port allocations to avoid test race conditions #152 --- .../Utilities.cs | 3 +++ .../Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index 31eb61ea07..d3440800bd 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -27,6 +27,9 @@ namespace Microsoft.AspNet.Server.WebListener { internal static class Utilities { + // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free + // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in + // Microsoft.Net.Http.Server. private const int BasePort = 5001; private const int MaxPort = 8000; private static int NextPort = BasePort; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs index fd732e11a4..c8bad49ad6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs @@ -6,8 +6,11 @@ namespace Microsoft.Net.Http.Server { internal static class Utilities { - private const int BasePort = 5001; - private const int MaxPort = 8000; + // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free + // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in + // Microsoft.AspNet.Server.WebListener. + private const int BasePort = 8001; + private const int MaxPort = 11000; private static int NextPort = BasePort; private static object PortLock = new object(); From 5444794c01501571c1801c9d953de94e138d3766 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Mon, 2 Nov 2015 16:42:44 -0800 Subject: [PATCH 270/597] Strong name everything. --- .../project.json | 3 ++- src/Microsoft.Net.Http.Server/project.json | 3 ++- src/Microsoft.Net.WebSockets/project.json | 3 ++- tools/Key.snk | Bin 0 -> 596 bytes 4 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 tools/Key.snk diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 683d0223a1..3151399176 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -7,7 +7,8 @@ "Microsoft.Net.Http.Server": "1.0.0-*" }, "compilationOptions": { - "allowUnsafe": true + "allowUnsafe": true, + "keyFile": "../../tools/Key.snk" }, "frameworks": { "dnx451": {}, diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 143a302dd8..884a7ce169 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -7,7 +7,8 @@ "Microsoft.Net.WebSockets": "1.0.0-*" }, "compilationOptions": { - "allowUnsafe": true + "allowUnsafe": true, + "keyFile": "../../tools/Key.snk" }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index b25f6378d3..f79c20c364 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -3,7 +3,8 @@ "description": "Implementation of WebSocket abstract base class. Used by WebListener.", "dependencies": {}, "compilationOptions": { - "allowUnsafe": true + "allowUnsafe": true, + "keyFile": "../../tools/Key.snk" }, "frameworks": { "net451": {}, diff --git a/tools/Key.snk b/tools/Key.snk new file mode 100644 index 0000000000000000000000000000000000000000..e10e4889c125d3120cd9e81582243d70f7cbb806 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098=Iw=HCsnz~#iVhm& zj%TU(_THUee?3yHBjk$37ysB?i5#7WD$={H zV4B!OxRPrb|8)HPg~A}8P>^=#y<)56#=E&NzcjOtPK~<4n6GHt=K$ro*T(lhby_@U zEk(hLzk1H)0yXj{A_5>fk-TgNoP|q6(tP2xo8zt8i%212CWM#AeCd?`hS|4~L({h~Moo(~vy&3Z z1uI}`fd^*>o=rwbAGymj6RM^pZm(*Kfhs+Y1#`-2JPWZMK8@;ZWCk2+9bX4YP);~fj-BU*R zQPvWv$89!{Rl9wM+zR>_TSkn^voYxA?2G iKnV#iZ6Ah`K>b=@=IjYJXrxL124zR(38)nxe+&q_$QXwJ literal 0 HcmV?d00001 From 34ae239e4f8ca52bbae7911f7ac99d0982752e70 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 3 Nov 2015 09:06:43 -0800 Subject: [PATCH 271/597] React to HttpAbstractions changes. --- .../HeaderDictionary.cs | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 src/Microsoft.AspNet.Server.WebListener/HeaderDictionary.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/HeaderDictionary.cs b/src/Microsoft.AspNet.Server.WebListener/HeaderDictionary.cs new file mode 100644 index 0000000000..7c78b196f7 --- /dev/null +++ b/src/Microsoft.AspNet.Server.WebListener/HeaderDictionary.cs @@ -0,0 +1,203 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using Microsoft.AspNet.Http; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNet.Server.WebListener +{ + /// + /// Represents a wrapper for RequestHeaders and ResponseHeaders. + /// + internal class HeaderDictionary : IHeaderDictionary + { + public HeaderDictionary(IDictionary store) + { + Store = store; + } + + private IDictionary Store { get; set; } + + /// + /// Get or sets the associated value from the collection as a single string. + /// + /// The header name. + /// the associated value from the collection as a StringValues or StringValues.Empty if the key is not present. + public StringValues this[string key] + { + get + { + StringValues value; + if (TryGetValue(key, out value)) + { + return value; + } + return StringValues.Empty; + } + set + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (StringValues.IsNullOrEmpty(value)) + { + Store.Remove(key); + } + else + { + Store[key] = value; + } + } + } + + /// + /// Throws KeyNotFoundException if the key is not present. + /// + /// The header name. + /// + StringValues IDictionary.this[string key] + { + get { return Store[key]; } + set { this[key] = value; } + } + + /// + /// Gets the number of elements contained in the ;. + /// + /// The number of elements contained in the . + public int Count + { + get { return Store.Count; } + } + + /// + /// Gets a value that indicates whether the is in read-only mode. + /// + /// true if the is in read-only mode; otherwise, false. + public bool IsReadOnly + { + get { return Store.IsReadOnly; } + } + + public ICollection Keys + { + get { return Store.Keys; } + } + + public ICollection Values + { + get { return Store.Values; } + } + + /// + /// Adds a new list of items to the collection. + /// + /// The item to add. + public void Add(KeyValuePair item) + { + Store.Add(item.Key, item.Value); + } + + /// + /// Adds the given header and values to the collection. + /// + /// The header name. + /// The header values. + public void Add(string key, StringValues value) + { + Store.Add(key, value); + } + + /// + /// Clears the entire list of objects. + /// + public void Clear() + { + Store.Clear(); + } + + /// + /// Returns a value indicating whether the specified object occurs within this collection. + /// + /// The item. + /// true if the specified object occurs within this collection; otherwise, false. + public bool Contains(KeyValuePair item) + { + return Store.Contains(item); + } + + /// + /// Determines whether the contains a specific key. + /// + /// The key. + /// true if the contains a specific key; otherwise, false. + public bool ContainsKey(string key) + { + return Store.ContainsKey(key); + } + + /// + /// Copies the elements to a one-dimensional Array instance at the specified index. + /// + /// The one-dimensional Array that is the destination of the specified objects copied from the . + /// The zero-based index in at which copying begins. + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + Store.CopyTo(array, arrayIndex); + } + + /// + /// Removes the given item from the the collection. + /// + /// The item. + /// true if the specified object was removed from the collection; otherwise, false. + public bool Remove(KeyValuePair item) + { + return Store.Remove(item); + } + + /// + /// Removes the given header from the collection. + /// + /// The header name. + /// true if the specified object was removed from the collection; otherwise, false. + public bool Remove(string key) + { + return Store.Remove(key); + } + + /// + /// Retrieves a value from the dictionary. + /// + /// The header name. + /// The value. + /// true if the contains the key; otherwise, false. + public bool TryGetValue(string key, out StringValues value) + { + return Store.TryGetValue(key, out value); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + public IEnumerator GetEnumerator() + { + return Store.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator> IEnumerable>.GetEnumerator() + { + return Store.GetEnumerator(); + } + } +} From 1a069df9794c8c842ae258c749b83d6b48e984cb Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 12 Nov 2015 12:23:38 -0800 Subject: [PATCH 272/597] Remove System beta tag in project.json for coreclr packages. --- samples/HelloWorld/project.json | 12 +++---- .../project.json | 6 ++-- src/Microsoft.Net.Http.Server/project.json | 14 ++++---- src/Microsoft.Net.WebSockets/project.json | 32 +++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index d2cd1453c9..3863f41615 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -9,12 +9,12 @@ "dnx451": { }, "dnxcore50": { "dependencies": { - "System.Collections": "4.0.11-beta-*", - "System.Console": "4.0.0-beta-*", - "System.Globalization": "4.0.11-beta-*", - "System.IO": "4.0.11-beta-*", - "System.Runtime": "4.0.21-beta-*", - "System.Threading.Tasks": "4.0.11-beta-*" + "System.Collections": "4.0.11-*", + "System.Console": "4.0.0-*", + "System.Globalization": "4.0.11-*", + "System.IO": "4.0.11-*", + "System.Runtime": "4.0.21-*", + "System.Threading.Tasks": "4.0.11-*" } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 3151399176..8852f2e655 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -15,13 +15,13 @@ "net451": { }, "dnxcore50": { "dependencies": { - "System.Security.Claims": "4.0.1-beta-*" + "System.Security.Claims": "4.0.1-*" } }, "dotnet5.4": { "dependencies": { - "System.Security.Claims": "4.0.1-beta-*" + "System.Security.Claims": "4.0.1-*" } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 884a7ce169..996fb117d7 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -15,13 +15,13 @@ "dotnet5.4": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.1-beta-*", - "System.Diagnostics.Debug": "4.0.11-beta-*", - "System.IO.FileSystem": "4.0.1-beta-*", - "System.Security.Claims": "4.0.1-beta-*", - "System.Security.Cryptography.X509Certificates": "4.0.0-beta-*", - "System.Security.Principal.Windows": "4.0.0-beta-*", - "System.Threading.Overlapped": "4.0.0-beta-*" + "System.Diagnostics.Debug": "4.0.11-*", + "System.IO.FileSystem": "4.0.1-*", + "System.Security.Claims": "4.0.1-*", + "System.Security.Cryptography.X509Certificates": "4.0.0-*", + "System.Security.Principal.Windows": "4.0.0-*", + "System.Threading.Overlapped": "4.0.0-*" } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets/project.json index f79c20c364..0273cd0f0b 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets/project.json @@ -10,22 +10,22 @@ "net451": {}, "dotnet5.4": { "dependencies": { - "System.Collections": "4.0.11-beta-*", - "System.Diagnostics.Contracts": "4.0.1-beta-*", - "System.Diagnostics.Tools": "4.0.1-beta-*", - "System.IO": "4.0.11-beta-*", - "System.Linq": "4.0.1-beta-*", - "System.Net.Primitives": "4.0.11-beta-*", - "System.Net.WebSockets": "4.0.0-beta-*", - "System.Resources.ResourceManager": "4.0.1-beta-*", - "System.Runtime.Extensions": "4.0.11-beta-*", - "System.Security.Cryptography.Algorithms": "4.0.0-beta-*", - "System.Text.Encoding.Extensions": "4.0.11-beta-*", - "System.Threading": "4.0.11-beta-*", - "System.Threading.Tasks": "4.0.11-beta-*", - "System.Threading.Timer": "4.0.1-beta-*", - "System.Threading.ThreadPool": "4.0.10-beta-*" + "System.Collections": "4.0.11-*", + "System.Diagnostics.Contracts": "4.0.1-*", + "System.Diagnostics.Tools": "4.0.1-*", + "System.IO": "4.0.11-*", + "System.Linq": "4.0.1-*", + "System.Net.Primitives": "4.0.11-*", + "System.Net.WebSockets": "4.0.0-*", + "System.Resources.ResourceManager": "4.0.1-*", + "System.Runtime.Extensions": "4.0.11-*", + "System.Security.Cryptography.Algorithms": "4.0.0-*", + "System.Text.Encoding.Extensions": "4.0.11-*", + "System.Threading": "4.0.11-*", + "System.Threading.Tasks": "4.0.11-*", + "System.Threading.Timer": "4.0.1-*", + "System.Threading.ThreadPool": "4.0.10-*" } } } -} \ No newline at end of file +} From a6055aebdaf8e711306618523558d77737a80d54 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 12 Nov 2015 15:27:49 -0800 Subject: [PATCH 273/597] Update Microsoft.Win32.Primitives reference's version --- src/Microsoft.Net.Http.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 996fb117d7..ec77bf8272 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -14,7 +14,7 @@ "net451": {}, "dotnet5.4": { "dependencies": { - "Microsoft.Win32.Primitives": "4.0.1-beta-*", + "Microsoft.Win32.Primitives": "4.0.1-*", "System.Diagnostics.Debug": "4.0.11-*", "System.IO.FileSystem": "4.0.1-*", "System.Security.Claims": "4.0.1-*", From 6ebc978f290e002e34ca05c9fe5910949e965a17 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 17 Nov 2015 10:34:35 -0800 Subject: [PATCH 274/597] Explicitly choose Mono 4.0.5 - avoids future problems related to aspnet/External#48 - e.g. when Travis updates default Mono version in `csharp` bundle --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 947bf868ee..dc44c0f660 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: csharp sudo: false +mono: + - 4.0.5 script: - ./build.sh --quiet verify \ No newline at end of file From 82c855d172eff8bc22f1ac471348591db3634756 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 17 Nov 2015 14:42:19 -0800 Subject: [PATCH 275/597] Move Travis to supported Linux distribution - use Ubuntu 14.04 (Trusty) - Travis support for Trusty is in Beta and currently requires `sudo` - run `dnu restore` with DNX Core since aspnet/External#49 is not fixed in Mono versions we can use - add required dependencies for DNX Core to `.travis.yml` - addresses part of aspnet/Universe#290 --- .travis.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc44c0f660..2fc624899f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,18 @@ language: csharp -sudo: false +sudo: required +dist: trusty +addons: + apt: + packages: + - gettext + - libcurl4-openssl-dev + - libicu-dev + - libssl-dev + - libunwind8 + - zlib1g +env: + - KOREBUILD_DNU_RESTORE_CORECLR=true mono: - 4.0.5 script: - - ./build.sh --quiet verify \ No newline at end of file + - ./build.sh --quiet verify From 8712ba4855eb770aeb8f1fce9a29d188ad99464a Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 3 Nov 2015 13:24:23 -0800 Subject: [PATCH 276/597] Reacting to new IServer IHttpApplication design --- .../MessagePump.cs | 58 +++++++++++++------ .../ServerFactory.cs | 7 +-- .../AuthenticationTests.cs | 2 - .../DummyApplication.cs | 51 ++++++++++++++++ .../HttpsTests.cs | 1 - .../RequestTests.cs | 6 +- .../ServerTests.cs | 6 +- .../Utilities.cs | 8 +-- 8 files changed, 100 insertions(+), 39 deletions(-) create mode 100644 test/Microsoft.AspNet.Server.WebListener.FunctionalTests/DummyApplication.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index acc5247da6..7476929f5e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -21,7 +21,6 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Features; using Microsoft.Extensions.Logging; @@ -35,9 +34,8 @@ namespace Microsoft.AspNet.Server.WebListener private readonly Microsoft.Net.Http.Server.WebListener _listener; private readonly ILogger _logger; - private readonly IHttpContextFactory _httpContextFactory; - private RequestDelegate _appFunc; + private IHttpApplication _application; private int _maxAccepts; private int _acceptorCounts; @@ -47,17 +45,16 @@ namespace Microsoft.AspNet.Server.WebListener private int _outstandingRequests; private ManualResetEvent _shutdownSignal; - internal MessagePump(Microsoft.Net.Http.Server.WebListener listener, ILoggerFactory loggerFactory, IFeatureCollection features, IHttpContextFactory httpContextFactory) + internal MessagePump(Microsoft.Net.Http.Server.WebListener listener, ILoggerFactory loggerFactory, IFeatureCollection features) { if (features == null) { - throw new ArgumentNullException(nameof(Features)); + throw new ArgumentNullException(nameof(features)); } Contract.Assert(listener != null); _listener = listener; _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); - _httpContextFactory = httpContextFactory; Features = features; _processRequest = new Action(ProcessRequestAsync); @@ -90,11 +87,11 @@ namespace Microsoft.AspNet.Server.WebListener public IFeatureCollection Features { get; } - public void Start(RequestDelegate app) + public void Start(IHttpApplication application) { - if (app == null) + if (application == null) { - throw new ArgumentNullException(nameof(app)); + throw new ArgumentNullException(nameof(application)); } var addressesFeature = Features.Get(); @@ -106,11 +103,11 @@ namespace Microsoft.AspNet.Server.WebListener ParseAddresses(addressesFeature.Addresses, Listener); // Can't call Start twice - Contract.Assert(_appFunc == null); + Contract.Assert(_application == null); - Contract.Assert(app != null); + Contract.Assert(application != null); - _appFunc = app; + _application = new ApplicationWrapper(application); if (_listener.UrlPrefixes.Count == 0) { @@ -183,14 +180,15 @@ namespace Microsoft.AspNet.Server.WebListener return; } - HttpContext httpContext = null; + object context = null; try { Interlocked.Increment(ref _outstandingRequests); FeatureContext featureContext = new FeatureContext(requestContext, EnableResponseCaching); - httpContext = _httpContextFactory.Create(featureContext.Features); - await _appFunc(httpContext).SupressContext(); + context = _application.CreateContext(featureContext.Features); + await _application.ProcessRequestAsync(context).SupressContext(); requestContext.Dispose(); + _application.DisposeContext(context, null); } catch (Exception ex) { @@ -205,13 +203,10 @@ namespace Microsoft.AspNet.Server.WebListener requestContext.Response.Reset(); SetFatalResponse(requestContext, 500); } + _application.DisposeContext(context, ex); } finally { - if (httpContext != null) - { - _httpContextFactory.Dispose(httpContext); - } if (Interlocked.Decrement(ref _outstandingRequests) == 0 && _stopping) { _shutdownSignal.Set(); @@ -253,5 +248,30 @@ namespace Microsoft.AspNet.Server.WebListener // All requests are finished _listener.Dispose(); } + + private class ApplicationWrapper : IHttpApplication + { + private readonly IHttpApplication _application; + + public ApplicationWrapper(IHttpApplication application) + { + _application = application; + } + + public object CreateContext(IFeatureCollection contextFeatures) + { + return _application.CreateContext(contextFeatures); + } + + public void DisposeContext(object context, Exception exception) + { + _application.DisposeContext((TContext)context, exception); + } + + public Task ProcessRequestAsync(object context) + { + return _application.ProcessRequestAsync((TContext)context); + } + } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs index 4775cad150..1e72371d8a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs @@ -37,7 +37,6 @@ using System; using System.Diagnostics.CodeAnalysis; using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Features; using Microsoft.Extensions.Configuration; @@ -51,12 +50,10 @@ namespace Microsoft.AspNet.Server.WebListener public class ServerFactory : IServerFactory { private ILoggerFactory _loggerFactory; - private IHttpContextFactory _httpContextFactory; - public ServerFactory(ILoggerFactory loggerFactory, IHttpContextFactory httpContextFactory) + public ServerFactory(ILoggerFactory loggerFactory) { _loggerFactory = loggerFactory; - _httpContextFactory = httpContextFactory; } /// @@ -72,7 +69,7 @@ namespace Microsoft.AspNet.Server.WebListener serverFeatures.Set(listener); serverFeatures.Set(SplitAddresses(configuration)); - return new MessagePump(listener, _loggerFactory, serverFeatures, _httpContextFactory); + return new MessagePump(listener, _loggerFactory, serverFeatures); } private IServerAddressesFeature SplitAddresses(IConfiguration config) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 89dac6caaa..d93c8b6579 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -20,9 +20,7 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; -using Microsoft.AspNet.Http.Internal; using Xunit; using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/DummyApplication.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/DummyApplication.cs new file mode 100644 index 0000000000..21c4aed52f --- /dev/null +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/DummyApplication.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Threading.Tasks; +using Microsoft.AspNet.Hosting.Server; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Features; +using Microsoft.AspNet.Http.Internal; + +namespace Microsoft.AspNet.Server.WebListener +{ + internal class DummyApplication : IHttpApplication + { + private readonly RequestDelegate _requestDelegate; + + public DummyApplication(RequestDelegate requestDelegate) + { + _requestDelegate = requestDelegate; + } + + public HttpContext CreateContext(IFeatureCollection contextFeatures) + { + return new DefaultHttpContext(contextFeatures); + } + + public void DisposeContext(HttpContext httpContext, Exception exception) + { + + } + + public async Task ProcessRequestAsync(HttpContext httpContext) + { + await _requestDelegate(httpContext); + } + } +} diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index 8a4595705d..ba18f67160 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -22,7 +22,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 424f536847..b31e02852a 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -20,11 +20,9 @@ using System.IO; using System.Net.Http; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.Hosting.Builder; using Microsoft.AspNet.Hosting.Server; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; using Microsoft.Net.Http.Server; using Xunit; @@ -171,7 +169,7 @@ namespace Microsoft.AspNet.Server.WebListener var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app); dynamicServer.Dispose(); var rootUri = new Uri(root); - var factory = new ServerFactory(loggerFactory: null, httpContextFactory: new HttpContextFactory(new HttpContextAccessor())); + var factory = new ServerFactory(loggerFactory: null); var server = factory.CreateServer(configuration: null); var listener = server.Features.Get(); @@ -180,7 +178,7 @@ namespace Microsoft.AspNet.Server.WebListener listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); } - server.Start(app); + server.Start(new DummyApplication(app)); return server; } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index 89127762de..d06ee8841c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -24,10 +24,8 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Hosting.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; using Microsoft.Net.Http.Server; using Xunit; @@ -253,7 +251,7 @@ namespace Microsoft.AspNet.Server.WebListener string address; using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } - var factory = new ServerFactory(loggerFactory: null, httpContextFactory: new HttpContextFactory(new HttpContextAccessor())); + var factory = new ServerFactory(loggerFactory: null); var server = factory.CreateServer(configuration: null); var listener = server.Features.Get(); listener.UrlPrefixes.Add(UrlPrefix.Create(address)); @@ -261,7 +259,7 @@ namespace Microsoft.AspNet.Server.WebListener using (server) { - server.Start(httpContext => Task.FromResult(0)); + server.Start(new DummyApplication(httpContext => Task.FromResult(0))); string response = await SendRequestAsync(address); Assert.Equal(string.Empty, response); } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs index d3440800bd..597f9aaf32 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs @@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Server.WebListener internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, out string root, out string baseAddress, RequestDelegate app) { - var factory = new ServerFactory(loggerFactory: null, httpContextFactory: Factory); + var factory = new ServerFactory(loggerFactory: null); lock (PortLock) { while (NextPort < MaxPort) @@ -73,7 +73,7 @@ namespace Microsoft.AspNet.Server.WebListener listener.AuthenticationManager.AuthenticationSchemes = authType; try { - server.Start(app); + server.Start(new DummyApplication(app)); return server; } catch (WebListenerException) @@ -92,10 +92,10 @@ namespace Microsoft.AspNet.Server.WebListener internal static IServer CreateServer(string scheme, string host, int port, string path, RequestDelegate app) { - var factory = new ServerFactory(loggerFactory: null, httpContextFactory: Factory); + var factory = new ServerFactory(loggerFactory: null); var server = factory.CreateServer(configuration: null); server.Features.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); - server.Start(app); + server.Start(new DummyApplication(app)); return server; } } From 7a310a35db634a2f050658474191013653c8ad2c Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Dec 2015 17:28:54 -0800 Subject: [PATCH 277/597] Reacting to verbose rename --- samples/SelfHostServer/Startup.cs | 2 +- src/Microsoft.AspNet.Server.WebListener/LogHelper.cs | 9 ++++----- src/Microsoft.AspNet.Server.WebListener/MessagePump.cs | 2 +- src/Microsoft.Net.Http.Server/LogHelper.cs | 4 ++-- .../RequestProcessing/Request.cs | 4 ++-- .../RequestProcessing/Response.cs | 4 ++-- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 1af91636e5..f9d7649562 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -17,7 +17,7 @@ namespace SelfHostServer var listener = app.ServerFeatures.Get(); listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; - loggerfactory.AddConsole(LogLevel.Verbose); + loggerfactory.AddConsole(LogLevel.Debug); app.Run(async context => { diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs index 727c2871f6..5db901b922 100644 --- a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs @@ -23,7 +23,6 @@ using System; using System.Diagnostics; -using System.Globalization; using Microsoft.Extensions.Logging; namespace Microsoft.AspNet.Server.WebListener @@ -52,7 +51,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal static void LogVerbose(ILogger logger, string data) + internal static void LogDebug(ILogger logger, string data) { if (logger == null) { @@ -60,13 +59,13 @@ namespace Microsoft.AspNet.Server.WebListener } else { - logger.LogVerbose(data); + logger.LogDebug(data); } } - internal static void LogVerbose(ILogger logger, string location, Exception exception) + internal static void LogDebug(ILogger logger, string location, Exception exception) { - LogVerbose(logger, location + "; " + exception.ToString()); + LogDebug(logger, location + "; " + exception.ToString()); } internal static void LogException(ILogger logger, string location, Exception exception) diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs index 7476929f5e..9cb66bc7ba 100644 --- a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs @@ -147,7 +147,7 @@ namespace Microsoft.AspNet.Server.WebListener Contract.Assert(_stopping); if (_stopping) { - LogHelper.LogVerbose(_logger, "ListenForNextRequestAsync-Stopping", exception); + LogHelper.LogDebug(_logger, "ListenForNextRequestAsync-Stopping", exception); } else { diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index cce8320132..da3c22ded3 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -51,7 +51,7 @@ namespace Microsoft.Net.Http.Server } } - internal static void LogVerbose(ILogger logger, string data) + internal static void LogDebug(ILogger logger, string data) { if (logger == null) { @@ -59,7 +59,7 @@ namespace Microsoft.Net.Http.Server } else { - logger.LogVerbose(data); + logger.LogDebug(data); } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 87186a1ef0..a38bd82ede 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -151,9 +151,9 @@ namespace Microsoft.Net.Http.Server // TODO: Verbose log parameters - if (_requestContext.Logger.IsEnabled(LogLevel.Verbose)) + if (_requestContext.Logger.IsEnabled(LogLevel.Debug)) { - RequestContext.Logger.LogVerbose(new ReceiveRequestLogContext(this)); + RequestContext.Logger.LogDebug(new ReceiveRequestLogContext(this)); } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index a23db82eaf..5c174ad74c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -356,9 +356,9 @@ namespace Microsoft.Net.Http.Server _responseState = ResponseState.StartedSending; var reasonPhrase = GetReasonPhrase(StatusCode); - if (RequestContext.Logger.IsEnabled(LogLevel.Verbose)) + if (RequestContext.Logger.IsEnabled(LogLevel.Debug)) { - RequestContext.Logger.LogVerbose(new SendResponseLogContext(this)); + RequestContext.Logger.LogDebug(new SendResponseLogContext(this)); } /* From fca0476936f2cc597eacab2792eb95512f52bdfd Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 2 Dec 2015 14:50:32 -0800 Subject: [PATCH 278/597] #137 Relayer and ifdef WebSockets Rename Microsoft.Net.WebSockets to Microsoft.Net.WebSockets.Server. Reverse dependency with Microsoft.Net.Http.Server. ifdef out IHttpWebSocketFeature. --- WebListener.sln | 4 +- samples/HelloWorld/Program.cs | 2 +- samples/HelloWorld/project.json | 3 +- .../FeatureContext.cs | 11 +- .../RequestProcessing/RequestContext.cs | 195 ---------------- src/Microsoft.Net.Http.Server/project.json | 8 +- .../HttpKnownHeaderNames.cs | 0 .../Legacy/SR.cs | 0 .../WebSocketHttpListenerDuplexStream.cs | 0 .../Microsoft.Net.WebSockets.Server.xproj} | 0 .../NativeInterop/SafeLoadLibrary.cs | 0 .../NativeInterop/SafeWebSocketHandle.cs | 0 .../NativeInterop/UnsafeNativeMethods.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ServerWebSocket.cs | 0 .../WebSocketBase.cs | 0 .../WebSocketBuffer.cs | 0 .../WebSocketConstants.cs | 0 .../WebSocketError.cs | 2 +- .../WebSocketException.cs | 4 +- .../WebSocketExtensions.cs | 217 ++++++++++++++++++ .../WebSocketHelpers.cs | 1 - .../WebSocketReceiveResultExtensions.cs | 2 +- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 0 .../fx/System/AccessViolationException.cs | 0 .../fx/System/ExternDll.cs | 0 .../InteropServices/ExternalException.cs | 0 .../fx/System/SafeNativeMethods.cs | 0 .../fx/System/SystemException.cs | 0 .../project.json | 9 +- .../System/ComponentModel/Win32Exception.cs | 129 ----------- .../WebSocketTests.cs | 6 +- .../WebSocketTests.cs | 2 +- .../project.json | 1 + 34 files changed, 245 insertions(+), 351 deletions(-) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/HttpKnownHeaderNames.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/Legacy/SR.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/Legacy/WebSocketHttpListenerDuplexStream.cs (100%) rename src/{Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj => Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj} (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/NativeInterop/SafeLoadLibrary.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/NativeInterop/SafeWebSocketHandle.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/NativeInterop/UnsafeNativeMethods.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/Properties/AssemblyInfo.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/ServerWebSocket.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/WebSocketBase.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/WebSocketBuffer.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/WebSocketConstants.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/WebSocketError.cs (97%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/WebSocketException.cs (99%) create mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketExtensions.cs rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/WebSocketHelpers.cs (99%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/WebSocketReceiveResultExtensions.cs (97%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/fx/System/AccessViolationException.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/fx/System/ExternDll.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/fx/System/Runtime/InteropServices/ExternalException.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/fx/System/SafeNativeMethods.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/fx/System/SystemException.cs (100%) rename src/{Microsoft.Net.WebSockets => Microsoft.Net.WebSockets.Server}/project.json (75%) delete mode 100644 src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs diff --git a/WebListener.sln b/WebListener.sln index 9f9ffbfbf5..618e975e97 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22710.0 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -17,7 +17,7 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\Hello EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.xproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.WebSockets", "src\Microsoft.Net.WebSockets\Microsoft.Net.WebSockets.xproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.WebSockets.Server", "src\Microsoft.Net.WebSockets.Server\Microsoft.Net.WebSockets.Server.xproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj", "{4492FF4C-9032-411D-853F-46B01755E504}" EndProject diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index eb57deedfc..2f62f082fe 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -59,7 +59,7 @@ namespace HelloWorld // Response byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); - if (context.IsWebSocketRequest) + if (context.IsWebSocketRequest()) { Console.WriteLine("WebSocket"); WebSocket webSocket = await context.AcceptWebSocketAsync(); diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 3863f41615..8f8d2299aa 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,6 +1,7 @@ { "dependencies": { - "Microsoft.Net.Http.Server": "1.0.0-*" + "Microsoft.Net.Http.Server": "1.0.0-*", + "Microsoft.Net.WebSockets.Server": "1.0.0-*" }, "commands": { "sample": "HelloWorld" diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index dbf84e121d..e311ebf82b 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -16,7 +16,6 @@ // permissions and limitations under the License. using System; -using System.Collections.Generic; using System.IO; using System.Net; using System.Net.WebSockets; @@ -27,8 +26,6 @@ using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; -using Microsoft.AspNet.Http.Internal; -using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Server; @@ -43,7 +40,9 @@ namespace Microsoft.AspNet.Server.WebListener ITlsTokenBindingFeature, IHttpBufferingFeature, IHttpRequestLifetimeFeature, +#if WEBSOCKETS IHttpWebSocketFeature, +#endif IHttpAuthenticationFeature, IHttpUpgradeFeature, IHttpRequestIdentifierFeature @@ -422,12 +421,12 @@ namespace Microsoft.AspNet.Server.WebListener { return _requestContext.UpgradeAsync(); } - +#if WEBSOCKETS bool IHttpWebSocketFeature.IsWebSocketRequest { get { - return _requestContext.IsWebSocketRequest; + return _requestContext.IsWebSocketRequest(); } } @@ -441,7 +440,7 @@ namespace Microsoft.AspNet.Server.WebListener } return _requestContext.AcceptWebSocketAsync(subProtocol); } - +#endif ClaimsPrincipal IHttpAuthenticationFeature.User { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 4c0b0a0c14..3fe3b9a9c8 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -24,14 +24,11 @@ using System; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Linq; -using System.Net.WebSockets; using System.Runtime.InteropServices; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using Microsoft.Net.WebSockets; namespace Microsoft.Net.Http.Server { @@ -174,198 +171,6 @@ namespace Microsoft.Net.Http.Server return Task.FromResult(opaqueStream); } - public bool IsWebSocketRequest - { - get - { - if (!WebSocketHelpers.AreWebSocketsSupported) - { - return false; - } - - if (!IsUpgradableRequest) - { - return false; - } - - if (!string.Equals("GET", Request.Method, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - string connection = Request.Headers[HttpKnownHeaderNames.Connection]; - if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) - { - return false; - } - - // Upgrade: websocket - string upgrade = Request.Headers[HttpKnownHeaderNames.Upgrade]; - if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Sec-WebSocket-Version: 13 - string version = Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Sec-WebSocket-Key: {base64string} - string key = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - if (!WebSocketHelpers.IsValidWebSocketKey(key)) - { - return false; - } - - return true; - } - } - - // Compare IsWebSocketRequest - private void ValidateWebSocketRequest() - { - if (!WebSocketHelpers.AreWebSocketsSupported) - { - throw new NotSupportedException("WebSockets are not supported on this platform."); - } - - if (!IsUpgradableRequest) - { - throw new InvalidOperationException("This request is not a valid upgrade request."); - } - - if (!string.Equals("GET", Request.Method, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("This request is not a valid upgrade request; invalid verb: " + Request.Method); - } - - // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - string connection = Request.Headers[HttpKnownHeaderNames.Connection]; - if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) - { - throw new InvalidOperationException("The Connection header is invalid: " + connection); - } - - // Upgrade: websocket - string upgrade = Request.Headers[HttpKnownHeaderNames.Upgrade]; - if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("The Upgrade header is invalid: " + upgrade); - } - - // Sec-WebSocket-Version: 13 - string version = Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("The Sec-WebSocket-Version header is invalid or not supported: " + version); - } - - // Sec-WebSocket-Key: {base64string} - string key = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - if (!WebSocketHelpers.IsValidWebSocketKey(key)) - { - throw new InvalidOperationException("The Sec-WebSocket-Key header is invalid: " + upgrade); - } - } - - public Task AcceptWebSocketAsync() - { - return AcceptWebSocketAsync(null, - WebSocketHelpers.DefaultReceiveBufferSize, - WebSocketHelpers.DefaultKeepAliveInterval); - } - - public Task AcceptWebSocketAsync(string subProtocol) - { - return AcceptWebSocketAsync(subProtocol, - WebSocketHelpers.DefaultReceiveBufferSize, - WebSocketHelpers.DefaultKeepAliveInterval); - } - - public Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval) - { - return AcceptWebSocketAsync(subProtocol, - WebSocketHelpers.DefaultReceiveBufferSize, - keepAliveInterval); - } - - public Task AcceptWebSocketAsync( - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval) - { - WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); - - ArraySegment internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - return this.AcceptWebSocketAsync(subProtocol, - receiveBufferSize, - keepAliveInterval, - internalBuffer); - } - - public Task AcceptWebSocketAsync( - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) - { - if (!IsUpgradableRequest) - { - throw new InvalidOperationException("This request is cannot be upgraded."); - } - WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); - WebSocketHelpers.ValidateArraySegment(internalBuffer, "internalBuffer"); - WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - - return AcceptWebSocketAsyncCore(subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer); - } - - private async Task AcceptWebSocketAsyncCore( - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) - { - try - { - ValidateWebSocketRequest(); - - var subProtocols = Request.Headers.GetValues(HttpKnownHeaderNames.SecWebSocketProtocol); - bool shouldSendSecWebSocketProtocolHeader = WebSocketHelpers.ProcessWebSocketProtocolHeader(subProtocols, subProtocol); - if (shouldSendSecWebSocketProtocolHeader) - { - Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = subProtocol; - } - - // negotiate the websocket key return value - string secWebSocketKey = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); - - Response.Headers.Append(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); - Response.Headers.Append(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); - Response.Headers.Append(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); - - Stream opaqueStream = await UpgradeAsync(); - - return WebSocketHelpers.CreateServerWebSocket( - opaqueStream, - subProtocol, - receiveBufferSize, - keepAliveInterval, - internalBuffer); - } - catch (Exception ex) - { - LogHelper.LogException(Logger, "AcceptWebSocketAsync", ex); - throw; - } - } - - /* public bool TryGetChannelBinding(ref ChannelBinding value) { diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index ec77bf8272..e72589e906 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -3,8 +3,7 @@ "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", - "Microsoft.Extensions.Primitives": "1.0.0-*", - "Microsoft.Net.WebSockets": "1.0.0-*" + "Microsoft.Extensions.Primitives": "1.0.0-*" }, "compilationOptions": { "allowUnsafe": true, @@ -15,11 +14,16 @@ "dotnet5.4": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.1-*", + "System.Diagnostics.Contracts": "4.0.1-*", "System.Diagnostics.Debug": "4.0.11-*", + "System.Diagnostics.Tools": "4.0.1-*", + "System.IO": "4.0.11-*", "System.IO.FileSystem": "4.0.1-*", + "System.Net.Primitives": "4.0.11-*", "System.Security.Claims": "4.0.1-*", "System.Security.Cryptography.X509Certificates": "4.0.0-*", "System.Security.Principal.Windows": "4.0.0-*", + "System.Text.Encoding.Extensions": "4.0.11-*", "System.Threading.Overlapped": "4.0.0-*" } } diff --git a/src/Microsoft.Net.WebSockets/HttpKnownHeaderNames.cs b/src/Microsoft.Net.WebSockets.Server/HttpKnownHeaderNames.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/HttpKnownHeaderNames.cs rename to src/Microsoft.Net.WebSockets.Server/HttpKnownHeaderNames.cs diff --git a/src/Microsoft.Net.WebSockets/Legacy/SR.cs b/src/Microsoft.Net.WebSockets.Server/Legacy/SR.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/Legacy/SR.cs rename to src/Microsoft.Net.WebSockets.Server/Legacy/SR.cs diff --git a/src/Microsoft.Net.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs b/src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/Legacy/WebSocketHttpListenerDuplexStream.cs rename to src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs diff --git a/src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj b/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj similarity index 100% rename from src/Microsoft.Net.WebSockets/Microsoft.Net.WebSockets.xproj rename to src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeLoadLibrary.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/NativeInterop/SafeLoadLibrary.cs rename to src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeLoadLibrary.cs diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/SafeWebSocketHandle.cs b/src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeWebSocketHandle.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/NativeInterop/SafeWebSocketHandle.cs rename to src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeWebSocketHandle.cs diff --git a/src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/NativeInterop/UnsafeNativeMethods.cs rename to src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs diff --git a/src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs b/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/Properties/AssemblyInfo.cs rename to src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.Net.WebSockets/ServerWebSocket.cs b/src/Microsoft.Net.WebSockets.Server/ServerWebSocket.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/ServerWebSocket.cs rename to src/Microsoft.Net.WebSockets.Server/ServerWebSocket.cs diff --git a/src/Microsoft.Net.WebSockets/WebSocketBase.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/WebSocketBase.cs rename to src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs diff --git a/src/Microsoft.Net.WebSockets/WebSocketBuffer.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/WebSocketBuffer.cs rename to src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs diff --git a/src/Microsoft.Net.WebSockets/WebSocketConstants.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketConstants.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/WebSocketConstants.cs rename to src/Microsoft.Net.WebSockets.Server/WebSocketConstants.cs diff --git a/src/Microsoft.Net.WebSockets/WebSocketError.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketError.cs similarity index 97% rename from src/Microsoft.Net.WebSockets/WebSocketError.cs rename to src/Microsoft.Net.WebSockets.Server/WebSocketError.cs index 11c84c27a5..09811b81c9 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketError.cs +++ b/src/Microsoft.Net.WebSockets.Server/WebSocketError.cs @@ -23,7 +23,7 @@ namespace Microsoft.Net.WebSockets { - public enum WebSocketError + internal enum WebSocketError { Success = 0, InvalidMessageType = 1, diff --git a/src/Microsoft.Net.WebSockets/WebSocketException.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs similarity index 99% rename from src/Microsoft.Net.WebSockets/WebSocketException.cs rename to src/Microsoft.Net.WebSockets.Server/WebSocketException.cs index 9724b91448..0ae7e4bb89 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketException.cs +++ b/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs @@ -115,7 +115,7 @@ namespace Microsoft.Net.WebSockets : base(message, innerException) { } - +#if !DOTNET5_4 public override int ErrorCode { get @@ -123,7 +123,7 @@ namespace Microsoft.Net.WebSockets return base.NativeErrorCode; } } - +#endif public WebSocketError WebSocketErrorCode { get diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketExtensions.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketExtensions.cs new file mode 100644 index 0000000000..dccc933241 --- /dev/null +++ b/src/Microsoft.Net.WebSockets.Server/WebSocketExtensions.cs @@ -0,0 +1,217 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.IO; +using System.Net.WebSockets; +using System.Threading.Tasks; +using Microsoft.Net.WebSockets; + +namespace Microsoft.Net.Http.Server +{ + public static class WebSocketExtensions + { + public static bool IsWebSocketRequest(this RequestContext context) + { + if (!WebSocketHelpers.AreWebSocketsSupported) + { + return false; + } + + if (!context.IsUpgradableRequest) + { + return false; + } + + if (!string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) + string connection = context.Request.Headers[HttpKnownHeaderNames.Connection]; + if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) + { + return false; + } + + // Upgrade: websocket + string upgrade = context.Request.Headers[HttpKnownHeaderNames.Upgrade]; + if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // Sec-WebSocket-Version: 13 + string version = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; + if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // Sec-WebSocket-Key: {base64string} + string key = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + if (!WebSocketHelpers.IsValidWebSocketKey(key)) + { + return false; + } + + return true; + } + + // Compare IsWebSocketRequest() + private static void ValidateWebSocketRequest(RequestContext context) + { + if (!WebSocketHelpers.AreWebSocketsSupported) + { + throw new NotSupportedException("WebSockets are not supported on this platform."); + } + + if (!context.IsUpgradableRequest) + { + throw new InvalidOperationException("This request is not a valid upgrade request."); + } + + if (!string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("This request is not a valid upgrade request; invalid verb: " + context.Request.Method); + } + + // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) + string connection = context.Request.Headers[HttpKnownHeaderNames.Connection]; + if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) + { + throw new InvalidOperationException("The Connection header is invalid: " + connection); + } + + // Upgrade: websocket + string upgrade = context.Request.Headers[HttpKnownHeaderNames.Upgrade]; + if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The Upgrade header is invalid: " + upgrade); + } + + // Sec-WebSocket-Version: 13 + string version = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; + if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The Sec-WebSocket-Version header is invalid or not supported: " + version); + } + + // Sec-WebSocket-Key: {base64string} + string key = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + if (!WebSocketHelpers.IsValidWebSocketKey(key)) + { + throw new InvalidOperationException("The Sec-WebSocket-Key header is invalid: " + upgrade); + } + } + + public static Task AcceptWebSocketAsync(this RequestContext context) + { + return context.AcceptWebSocketAsync(null, + WebSocketHelpers.DefaultReceiveBufferSize, + WebSocketHelpers.DefaultKeepAliveInterval); + } + + public static Task AcceptWebSocketAsync(this RequestContext context, string subProtocol) + { + return context.AcceptWebSocketAsync(subProtocol, + WebSocketHelpers.DefaultReceiveBufferSize, + WebSocketHelpers.DefaultKeepAliveInterval); + } + + public static Task AcceptWebSocketAsync(this RequestContext context, string subProtocol, TimeSpan keepAliveInterval) + { + return context.AcceptWebSocketAsync(subProtocol, + WebSocketHelpers.DefaultReceiveBufferSize, + keepAliveInterval); + } + + public static Task AcceptWebSocketAsync( + this RequestContext context, + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval) + { + WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); + + ArraySegment internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + return context.AcceptWebSocketAsync(subProtocol, + receiveBufferSize, + keepAliveInterval, + internalBuffer); + } + + public static Task AcceptWebSocketAsync( + this RequestContext context, + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + { + if (!context.IsUpgradableRequest) + { + throw new InvalidOperationException("This request is cannot be upgraded."); + } + WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); + WebSocketHelpers.ValidateArraySegment(internalBuffer, "internalBuffer"); + WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); + + return AcceptWebSocketAsyncCore(context, subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer); + } + + private static async Task AcceptWebSocketAsyncCore( + RequestContext context, + string subProtocol, + int receiveBufferSize, + TimeSpan keepAliveInterval, + ArraySegment internalBuffer) + { + ValidateWebSocketRequest(context); + + var subProtocols = context.Request.Headers.GetValues(HttpKnownHeaderNames.SecWebSocketProtocol); + bool shouldSendSecWebSocketProtocolHeader = WebSocketHelpers.ProcessWebSocketProtocolHeader(subProtocols, subProtocol); + if (shouldSendSecWebSocketProtocolHeader) + { + context.Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = subProtocol; + } + + // negotiate the websocket key return value + string secWebSocketKey = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); + + context.Response.Headers.Append(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); + context.Response.Headers.Append(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); + context.Response.Headers.Append(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); + + Stream opaqueStream = await context.UpgradeAsync(); + + return WebSocketHelpers.CreateServerWebSocket( + opaqueStream, + subProtocol, + receiveBufferSize, + keepAliveInterval, + internalBuffer); + } + } +} diff --git a/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketHelpers.cs similarity index 99% rename from src/Microsoft.Net.WebSockets/WebSocketHelpers.cs rename to src/Microsoft.Net.WebSockets.Server/WebSocketHelpers.cs index fc8a830408..21e0b11838 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketHelpers.cs +++ b/src/Microsoft.Net.WebSockets.Server/WebSocketHelpers.cs @@ -92,7 +92,6 @@ namespace Microsoft.Net.WebSockets } } - public static bool IsValidWebSocketKey(string key) { if (string.IsNullOrWhiteSpace(key)) diff --git a/src/Microsoft.Net.WebSockets/WebSocketReceiveResultExtensions.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketReceiveResultExtensions.cs similarity index 97% rename from src/Microsoft.Net.WebSockets/WebSocketReceiveResultExtensions.cs rename to src/Microsoft.Net.WebSockets.Server/WebSocketReceiveResultExtensions.cs index 00df192c38..12841af2df 100644 --- a/src/Microsoft.Net.WebSockets/WebSocketReceiveResultExtensions.cs +++ b/src/Microsoft.Net.WebSockets.Server/WebSocketReceiveResultExtensions.cs @@ -27,7 +27,7 @@ using System.Net.WebSockets; namespace Microsoft.Net.WebSockets { - public static class WebSocketReceiveResultExtensions + internal static class WebSocketReceiveResultExtensions { internal static WebSocketReceiveResult DecrementAndClone(ref WebSocketReceiveResult original, int count) { diff --git a/src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs rename to src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs diff --git a/src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/fx/System/AccessViolationException.cs rename to src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs diff --git a/src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/fx/System/ExternDll.cs rename to src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs diff --git a/src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/fx/System/Runtime/InteropServices/ExternalException.cs rename to src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs diff --git a/src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/fx/System/SafeNativeMethods.cs rename to src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs diff --git a/src/Microsoft.Net.WebSockets/fx/System/SystemException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs similarity index 100% rename from src/Microsoft.Net.WebSockets/fx/System/SystemException.cs rename to src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs diff --git a/src/Microsoft.Net.WebSockets/project.json b/src/Microsoft.Net.WebSockets.Server/project.json similarity index 75% rename from src/Microsoft.Net.WebSockets/project.json rename to src/Microsoft.Net.WebSockets.Server/project.json index 0273cd0f0b..140c3637b5 100644 --- a/src/Microsoft.Net.WebSockets/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -1,7 +1,9 @@ { "version": "1.0.0-*", "description": "Implementation of WebSocket abstract base class. Used by WebListener.", - "dependencies": {}, + "dependencies": { + "Microsoft.Net.Http.Server": "1.0.0-*" + }, "compilationOptions": { "allowUnsafe": true, "keyFile": "../../tools/Key.snk" @@ -11,16 +13,11 @@ "dotnet5.4": { "dependencies": { "System.Collections": "4.0.11-*", - "System.Diagnostics.Contracts": "4.0.1-*", - "System.Diagnostics.Tools": "4.0.1-*", - "System.IO": "4.0.11-*", "System.Linq": "4.0.1-*", - "System.Net.Primitives": "4.0.11-*", "System.Net.WebSockets": "4.0.0-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.0.11-*", "System.Security.Cryptography.Algorithms": "4.0.0-*", - "System.Text.Encoding.Extensions": "4.0.11-*", "System.Threading": "4.0.11-*", "System.Threading.Tasks": "4.0.11-*", "System.Threading.Timer": "4.0.1-*", diff --git a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs deleted file mode 100644 index 5c6d0dea8b..0000000000 --- a/src/Microsoft.Net.WebSockets/fx/System/ComponentModel/Win32Exception.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -#if DOTNET5_4 - -using System.Runtime.InteropServices; -using System.Text; - -namespace System.ComponentModel -{ - internal class Win32Exception : ExternalException - { - /// - /// Represents the Win32 error code associated with this exception. This - /// field is read-only. - /// - private readonly int nativeErrorCode; - - /// - /// Initializes a new instance of the class with the last Win32 error - /// that occured. - /// - public Win32Exception() - : this(Marshal.GetLastWin32Error()) - { - } - /// - /// Initializes a new instance of the class with the specified error. - /// - public Win32Exception(int error) - : this(error, GetErrorMessage(error)) - { - } - /// - /// Initializes a new instance of the class with the specified error and the - /// specified detailed description. - /// - public Win32Exception(int error, string message) - : base(message) - { - nativeErrorCode = error; - } - - /// - /// Initializes a new instance of the Exception class with a specified error message. - /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. - /// - public Win32Exception(string message) - : this(Marshal.GetLastWin32Error(), message) - { - } - - /// - /// Initializes a new instance of the Exception class with a specified error message and a - /// reference to the inner exception that is the cause of this exception. - /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. - /// - public Win32Exception(string message, Exception innerException) - : base(message, innerException) - { - nativeErrorCode = Marshal.GetLastWin32Error(); - } - - - /// - /// Represents the Win32 error code associated with this exception. This - /// field is read-only. - /// - public int NativeErrorCode - { - get - { - return nativeErrorCode; - } - } - - private static string GetErrorMessage(int error) - { - //get the system error message... - string errorMsg = ""; - StringBuilder sb = new StringBuilder(256); - int result = SafeNativeMethods.FormatMessage( - SafeNativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS | - SafeNativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | - SafeNativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY, - IntPtr.Zero, (uint)error, 0, sb, sb.Capacity + 1, - null); - if (result != 0) - { - int i = sb.Length; - while (i > 0) - { - char ch = sb[i - 1]; - if (ch > 32 && ch != '.') break; - i--; - } - errorMsg = sb.ToString(0, i); - } - else - { - errorMsg = "Unknown error (0x" + Convert.ToString(error, 16) + ")"; - } - - return errorMsg; - } - } -} - -#endif diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs index b6e55b1875..c39ae4b1d8 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -14,7 +14,7 @@ // NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing // permissions and limitations under the License. - +#if WEBSOCKETS using System; using System.Net.Http; using System.Net.WebSockets; @@ -22,7 +22,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Testing.xunit; using Xunit; @@ -165,4 +164,5 @@ namespace Microsoft.AspNet.Server.WebListener return client; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index 8a9d696905..083d02601f 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -62,7 +62,7 @@ namespace Microsoft.Net.Http.Server Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); var context = await server.GetContextAsync(); - Assert.True(context.IsWebSocketRequest); + Assert.True(context.IsWebSocketRequest()); WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); WebSocket clientWebSocket = await clientTask; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 586047d801..aba7cd14c8 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -4,6 +4,7 @@ }, "dependencies": { "Microsoft.Net.Http.Server": "1.0.0-*", + "Microsoft.Net.WebSockets.Server": "1.0.0-*", "Microsoft.AspNet.Testing": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, From f33ce786584a6f84a2d302d808970a94d88fa376 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 8 Dec 2015 12:41:46 -0800 Subject: [PATCH 279/597] Update WebSockets in NuGetPackageVerifier. --- NuGetPackageVerifier.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 709de17154..3c2d007f30 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -11,7 +11,7 @@ "packages": { "Microsoft.AspNet.Server.WebListener": { }, "Microsoft.Net.Http.Server": { }, - "Microsoft.Net.WebSockets": { } + "Microsoft.Net.WebSockets.Server": { } } }, "Default": { // Ru les to run for packages not listed in any other set. From 94dd583a15e32d3263e2166bbfa92b3e9311a0e4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 8 Dec 2015 18:51:32 -0800 Subject: [PATCH 280/597] Fixing CoreCLR package versions --- src/Microsoft.Net.Http.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index e72589e906..9cac2b5ca4 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -24,7 +24,7 @@ "System.Security.Cryptography.X509Certificates": "4.0.0-*", "System.Security.Principal.Windows": "4.0.0-*", "System.Text.Encoding.Extensions": "4.0.11-*", - "System.Threading.Overlapped": "4.0.0-*" + "System.Threading.Overlapped": "4.0.1-*" } } } From 3b42433f07106225a8d1bde8e227990b82967a52 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 9 Dec 2015 10:34:29 -0800 Subject: [PATCH 281/597] Handle null valued headers #158 --- .../RequestProcessing/Response.cs | 23 ++++---- .../ResponseHeaderTests.cs | 54 ++++++++++++++++++- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 5c174ad74c..a7d00602ce 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -575,7 +575,6 @@ namespace Microsoft.Net.Http.Server { if (headerPair.Value.Count == 0) { - // TODO: Have the collection exclude empty headers. continue; } // See if this is an unknown header @@ -602,7 +601,6 @@ namespace Microsoft.Net.Http.Server { if (headerPair.Value.Count == 0) { - // TODO: Have the collection exclude empty headers. continue; } headerName = headerPair.Key; @@ -632,7 +630,7 @@ namespace Microsoft.Net.Http.Server unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pName = (sbyte*)gcHandle.AddrOfPinnedObject(); // Add Value - headerValue = headerValues[headerValueIndex]; + headerValue = headerValues[headerValueIndex] ?? string.Empty; bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length; HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); @@ -644,16 +642,13 @@ namespace Microsoft.Net.Http.Server } else if (headerPair.Value.Count == 1) { - headerValue = headerValues[0]; - if (headerValue != null) - { - bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; - pKnownHeaders[lookup].RawValueLength = (ushort)bytes.Length; - HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); - gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - pinnedHeaders.Add(gcHandle); - pKnownHeaders[lookup].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); - } + headerValue = headerValues[0] ?? string.Empty; + bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + pKnownHeaders[lookup].RawValueLength = (ushort)bytes.Length; + HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); + gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + pinnedHeaders.Add(gcHandle); + pKnownHeaders[lookup].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); } else { @@ -681,7 +676,7 @@ namespace Microsoft.Net.Http.Server for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Value - headerValue = headerValues[headerValueIndex]; + headerValue = headerValues[headerValueIndex] ?? string.Empty; bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index bd8bb9cf5f..08b422d815 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -23,7 +23,7 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; +using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.AspNet.Server.WebListener @@ -259,6 +259,58 @@ namespace Microsoft.AspNet.Server.WebListener } } + [Theory, MemberData(nameof(NullHeaderData))] + public async Task Headers_IgnoreNullHeaders(string headerName, StringValues headerValue, StringValues expectedValue) + { + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + var responseHeaders = httpContext.Response.Headers; + responseHeaders.Add(headerName, headerValue); + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(address); + response.EnsureSuccessStatusCode(); + var headers = response.Headers; + + if (expectedValue.Count == 0) + { + Assert.False(headers.Contains(headerName)); + } + else + { + Assert.True(headers.Contains(headerName)); + Assert.Equal(headers.GetValues(headerName), expectedValue); + } + } + } + + public static TheoryData NullHeaderData + { + get + { + var dataset = new TheoryData(); + + // Unknown headers + dataset.Add("NullString", (string)null, (string)null); + dataset.Add("EmptyString", "", ""); + dataset.Add("NullStringArray", new string[] { null }, ""); + dataset.Add("EmptyStringArray", new string[] { "" }, ""); + dataset.Add("MixedStringArray", new string[] { null, "" }, new string[] { "", "" }); + // Known headers + dataset.Add("Location", (string)null, (string)null); + dataset.Add("Location", "", (string)null); + dataset.Add("Location", new string[] { null }, (string)null); + dataset.Add("Location", new string[] { "" }, (string)null); + dataset.Add("Location", new string[] { "a" }, "a"); + dataset.Add("Location", new string[] { null, "" }, (string)null); + dataset.Add("Location", new string[] { null, "", "a", "b" }, new string[] { "a", "b" }); + + return dataset; + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) From 098b2423b27b394f98fc44a5136e8dda4ed366da Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 11 Dec 2015 12:23:15 -0800 Subject: [PATCH 282/597] Updating to release NuGet.config. --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 1707938c61..9db87a421e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file From de8c74bb892564a80868528583c26bed6e81802f Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 16 Dec 2015 09:14:33 -0800 Subject: [PATCH 283/597] Add missing System.Runtime.InteropServices dependency. --- src/Microsoft.Net.Http.Server/project.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 9cac2b5ca4..f67b5bac6c 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -20,6 +20,7 @@ "System.IO": "4.0.11-*", "System.IO.FileSystem": "4.0.1-*", "System.Net.Primitives": "4.0.11-*", + "System.Runtime.InteropServices": "4.0.21-*", "System.Security.Claims": "4.0.1-*", "System.Security.Cryptography.X509Certificates": "4.0.0-*", "System.Security.Principal.Windows": "4.0.0-*", From 2dc31546b64bbfb7e49ad71a64b957b41d24f2cb Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 17 Dec 2015 09:19:25 -0800 Subject: [PATCH 284/597] #162 Remove an extra websocket reference. --- .../StandardFeatureCollection.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs index f3f302a6b2..b00cfb6bb7 100644 --- a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs @@ -38,7 +38,9 @@ namespace Microsoft.AspNet.Server.WebListener { typeof(IHttpBufferingFeature), _identityFunc }, { typeof(IHttpRequestLifetimeFeature), _identityFunc }, { typeof(IHttpUpgradeFeature), _identityFunc }, +#if WEBSOCKETS { typeof(IHttpWebSocketFeature), _identityFunc }, +#endif { typeof(IHttpAuthenticationFeature), _identityFunc }, { typeof(IHttpRequestIdentifierFeature), _identityFunc }, { typeof(RequestContext), ctx => ctx.RequestContext }, From fdf0b8413617faf663faadc49eb5b7b7871d506b Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 17 Dec 2015 16:47:55 -0800 Subject: [PATCH 285/597] Reacting to new Hosting API --- samples/HotAddSample/Startup.cs | 11 ++++++ samples/HotAddSample/hosting.json | 4 ++ samples/HotAddSample/project.json | 27 ++++++++------ samples/SelfHostServer/Startup.cs | 11 ++++++ samples/SelfHostServer/hosting.json | 4 ++ samples/SelfHostServer/project.json | 21 ++++++----- .../Program.cs | 37 ------------------- 7 files changed, 57 insertions(+), 58 deletions(-) create mode 100644 samples/HotAddSample/hosting.json create mode 100644 samples/SelfHostServer/hosting.json delete mode 100644 src/Microsoft.AspNet.Server.WebListener/Program.cs diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index c3e618e1df..6da3251b00 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -1,5 +1,6 @@ using System; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Server.Features; @@ -86,5 +87,15 @@ namespace HotAddSample await context.Response.WriteAsync(""); }); } + + public static void Main(string[] args) + { + var application = new WebApplicationBuilder() + .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + .UseStartup() + .Build(); + + application.Run(); + } } } diff --git a/samples/HotAddSample/hosting.json b/samples/HotAddSample/hosting.json new file mode 100644 index 0000000000..2efa8f78a3 --- /dev/null +++ b/samples/HotAddSample/hosting.json @@ -0,0 +1,4 @@ +{ + "server": "Microsoft.AspNet.Server.WebListener", + "server.urls": "http://localhost:12345" +} diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index ade404891b..4b5d9cf38d 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,14 +1,17 @@ { - "version": "1.0.0-*", - "dependencies": { - "Microsoft.AspNet.Server.WebListener": "1.0.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" - }, - "commands": { - "web": "Microsoft.AspNet.Server.WebListener --server.urls http://localhost:12345" - }, - "frameworks" : { - "dnx451" : { }, - "dnxcore50" : { } - } + "version": "1.0.0-*", + "dependencies": { + "Microsoft.AspNet.Server.WebListener": "1.0.0-*", + "Microsoft.Extensions.Logging.Console": "1.0.0-*" + }, + "compilationOptions": { + "emitEntryPoint": true + }, + "commands": { + "web": "HotAddSample" + }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { } + } } diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index f9d7649562..377cc3eb63 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -3,6 +3,7 @@ using System.Net.WebSockets; using System.Text; using System.Threading; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.Extensions.Logging; @@ -36,5 +37,15 @@ namespace SelfHostServer } }); } + + public static void Main(string[] args) + { + var application = new WebApplicationBuilder() + .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + .UseStartup() + .Build(); + + application.Run(); + } } } diff --git a/samples/SelfHostServer/hosting.json b/samples/SelfHostServer/hosting.json new file mode 100644 index 0000000000..6ac58d83c9 --- /dev/null +++ b/samples/SelfHostServer/hosting.json @@ -0,0 +1,4 @@ +{ + "server": "Microsoft.AspNet.Server.WebListener", + "server.urls": "http://localhost:8080" +} diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index ec72077179..d0e19d44c0 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,11 +1,14 @@ { - "dependencies": { - "Microsoft.AspNet.Server.WebListener": "1.0.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" - }, - "commands": { "web": "Microsoft.AspNet.Server.WebListener --server.urls http://localhost:8080" }, - "frameworks": { - "dnx451": { }, - "dnxcore50": { } - } + "dependencies": { + "Microsoft.AspNet.Server.WebListener": "1.0.0-*", + "Microsoft.Extensions.Logging.Console": "1.0.0-*" + }, + "compilationOptions": { + "emitEntryPoint": true + }, + "commands": { "web": "SelfHostServer" }, + "frameworks": { + "dnx451": { }, + "dnxcore50": { } + } } diff --git a/src/Microsoft.AspNet.Server.WebListener/Program.cs b/src/Microsoft.AspNet.Server.WebListener/Program.cs deleted file mode 100644 index a13e2ed125..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/Program.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- - -using System; -using System.Linq; - -namespace Microsoft.AspNet.Server.WebListener -{ - public class Program - { - public static void Main(string[] args) - { - var mergedArgs = new[] { "--server", "Microsoft.AspNet.Server.WebListener" }.Concat(args).ToArray(); - Hosting.Program.Main(mergedArgs); - } - } -} From 905b5bcfc2a037bc06378aa2339b96a03b56fcbc Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Wed, 16 Dec 2015 19:20:18 -0800 Subject: [PATCH 286/597] Enable tests on CoreCLR (#143). --- .../AuthenticationTests.cs | 19 ++++++--- .../HttpsTests.cs | 12 +++++- .../OpaqueUpgradeTests.cs | 4 +- .../RequestBodyTests.cs | 3 +- .../RequestHeaderTests.cs | 2 +- .../ResponseBodyTests.cs | 11 +++-- .../ResponseHeaderTests.cs | 10 ++++- .../ResponseSendFileTests.cs | 3 +- .../ServerTests.cs | 12 ++++-- .../project.json | 7 ++++ .../AuthenticationTests.cs | 12 +++--- .../HttpsTests.cs | 8 ++++ .../OpaqueUpgradeTests.cs | 2 +- .../RequestBodyTests.cs | 2 +- .../RequestHeaderTests.cs | 2 +- .../ResponseBodyTests.cs | 19 +++++---- .../ResponseCachingTests.cs | 41 ++++++++++++------- .../ResponseHeaderTests.cs | 10 ++++- .../ResponseSendFileTests.cs | 6 +-- .../ServerTests.cs | 6 +-- .../SkipOffDomainAttribute.cs | 5 ++- .../project.json | 8 ++++ 22 files changed, 143 insertions(+), 61 deletions(-) diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs index d93c8b6579..2b5d570844 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -21,6 +21,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.AspNet.Testing.xunit; using Xunit; using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes; @@ -52,11 +53,12 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented [InlineData(AuthenticationSchemes.Basic)] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; @@ -71,11 +73,12 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented [InlineData(AuthenticationSchemes.Basic)] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; @@ -94,7 +97,8 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Fact] + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; @@ -293,12 +297,13 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { string address; @@ -317,12 +322,13 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { string address; @@ -344,11 +350,12 @@ namespace Microsoft.AspNet.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationSchemes authType) { string address; diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs index ba18f67160..3027f4bc70 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -115,7 +115,11 @@ namespace Microsoft.AspNet.Server.WebListener private async Task SendRequestAsync(string uri, X509Certificate cert = null) { - WebRequestHandler handler = new WebRequestHandler(); +#if DNX451 + var handler = new WebRequestHandler(); +#else + var handler = new WinHttpHandler(); +#endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; if (cert != null) { @@ -129,7 +133,11 @@ namespace Microsoft.AspNet.Server.WebListener private async Task SendRequestAsync(string uri, string upload) { - WebRequestHandler handler = new WebRequestHandler(); +#if DNX451 + var handler = new WebRequestHandler(); +#else + var handler = new WinHttpHandler(); +#endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; using (HttpClient client = new HttpClient(handler)) { diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 4949bd10bb..0db487cd09 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -24,7 +24,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Testing.xunit; using Xunit; @@ -218,6 +217,7 @@ namespace Microsoft.AspNet.Server.WebListener // Connect with a socket Uri uri = new Uri(address); TcpClient client = new TcpClient(); + try { await client.ConnectAsync(uri.Host, uri.Port); @@ -235,7 +235,7 @@ namespace Microsoft.AspNet.Server.WebListener } catch (Exception) { - client.Close(); + ((IDisposable)client).Dispose(); throw; } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs index b17639491e..58a1de5318 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -191,6 +191,7 @@ namespace Microsoft.AspNet.Server.WebListener // Connect with a socket Uri uri = new Uri(address); TcpClient client = new TcpClient(); + try { await client.ConnectAsync(uri.Host, uri.Port); @@ -204,7 +205,7 @@ namespace Microsoft.AspNet.Server.WebListener } catch (Exception) { - client.Close(); + ((IDisposable)client).Dispose(); throw; } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index f4fd3c378c..62f7a36708 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -107,7 +107,7 @@ namespace Microsoft.AspNet.Server.WebListener byte[] response = new byte[1024 * 5]; await Task.Run(() => socket.Receive(response)); - socket.Close(); + socket.Dispose(); } } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 2b5800f205..68a214cc83 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -25,6 +25,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.AspNet.Server.WebListener @@ -78,7 +79,7 @@ namespace Microsoft.AspNet.Server.WebListener string address; using (Utilities.CreateHttpServer(out address, async httpContext => { - httpContext.Response.Headers["transfeR-Encoding"] = " CHunked "; + httpContext.Response.Headers["transfeR-Encoding"] = "CHunked"; Stream stream = httpContext.Response.Body; var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); await stream.WriteAsync(responseBytes, 0, responseBytes.Length); @@ -98,13 +99,17 @@ namespace Microsoft.AspNet.Server.WebListener public async Task ResponseBody_WriteContentLength_PassedThrough() { string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (Utilities.CreateHttpServer(out address, async httpContext => { httpContext.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = httpContext.Response.Body; +#if DNX451 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); +#else + await stream.WriteAsync(new byte[10], 0, 10); +#endif stream.Write(new byte[10], 0, 10); - return stream.WriteAsync(new byte[10], 0, 10); + await stream.WriteAsync(new byte[10], 0, 10); })) { HttpResponseMessage response = await SendRequestAsync(address); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 08b422d815..65cc7ba379 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); - Assert.Equal(new string[] { "custom1" }, response.Headers.GetValues("WWW-Authenticate")); + Assert.Equal("custom1", response.Headers["WWW-Authenticate"]); } } @@ -94,7 +94,11 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); +#if DNXCORE50 // WebHeaderCollection.GetValues() not available in CoreCLR. + Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); +#else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); +#endif } } @@ -118,7 +122,11 @@ namespace Microsoft.AspNet.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); +#if DNXCORE50 // WebHeaderCollection.GetValues() not available in CoreCLR. + Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); +#else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); +#endif } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 751d4d0e40..48ef151349 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -25,7 +25,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; using Xunit; namespace Microsoft.AspNet.Server.WebListener @@ -38,7 +37,7 @@ namespace Microsoft.AspNet.Server.WebListener public ResponseSendFileTests() { - AbsoluteFilePath = Directory.GetFiles(Environment.CurrentDirectory).First(); + AbsoluteFilePath = Directory.GetFiles(Directory.GetCurrentDirectory()).First(); RelativeFilePath = Path.GetFileName(AbsoluteFilePath); FileLength = new FileInfo(AbsoluteFilePath).Length; } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs index d06ee8841c..15ca0a7754 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs @@ -207,7 +207,11 @@ namespace Microsoft.AspNet.Server.WebListener using (Socket socket = await SendHungRequestAsync("GET", address)) { Assert.True(received.WaitOne(interval), "Receive Timeout"); - socket.Close(0); // Force a RST + + // Force a RST + socket.LingerState = new LingerOption(true, 0); + socket.Dispose(); + aborted.Set(); } Assert.True(canceled.WaitOne(interval), "canceled"); @@ -267,7 +271,6 @@ namespace Microsoft.AspNet.Server.WebListener private async Task SendRequestAsync(string uri) { - ServicePointManager.DefaultConnectionLimit = 100; using (HttpClient client = new HttpClient()) { return await client.GetStringAsync(uri); @@ -289,6 +292,7 @@ namespace Microsoft.AspNet.Server.WebListener // Connect with a socket Uri uri = new Uri(address); TcpClient client = new TcpClient(); + try { await client.ConnectAsync(uri.Host, uri.Port); @@ -297,13 +301,13 @@ namespace Microsoft.AspNet.Server.WebListener // Send an HTTP GET request byte[] requestBytes = BuildGetRequest(method, uri); await stream.WriteAsync(requestBytes, 0, requestBytes.Length); - + // Return the opaque network stream return client.Client; } catch (Exception) { - client.Close(); + ((IDisposable)client).Dispose(); throw; } } diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 1edc19d889..9fee80e2f2 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -13,6 +13,13 @@ "System.Net.Http": "", "System.Net.Http.WebRequest": "" } + }, + "dnxcore50": { + "dependencies": { + "System.Net.Http.WinHttpHandler": "4.0.0-*", + "System.Net.Requests": "4.0.11-*", + "System.Net.WebHeaderCollection": "4.0.1-*" + } } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 7c4272cd51..8281eb53fa 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -44,11 +44,12 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented [InlineData(AuthenticationSchemes.Basic)] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; @@ -57,18 +58,18 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(address); var contextTask = server.GetContextAsync(); // Fails when the server shuts down, the challenge happens internally. - var response = await responseTask; Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented [InlineData(AuthenticationSchemes.Basic)] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; @@ -89,7 +90,8 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; @@ -216,7 +218,7 @@ namespace Microsoft.Net.Http.Server { HttpClientHandler handler = new HttpClientHandler(); handler.UseDefaultCredentials = useDefaultCredentials; - using (HttpClient client = new HttpClient(handler)) + using (HttpClient client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(5) }) { return await client.GetAsync(uri); } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index 5483589211..05931b0ad1 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -107,7 +107,11 @@ namespace Microsoft.Net.Http.Server private async Task SendRequestAsync(string uri, X509Certificate cert = null) { +#if DNX451 WebRequestHandler handler = new WebRequestHandler(); +#else + WinHttpHandler handler = new WinHttpHandler(); +#endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; if (cert != null) { @@ -121,7 +125,11 @@ namespace Microsoft.Net.Http.Server private async Task SendRequestAsync(string uri, string upload) { +#if DNX451 WebRequestHandler handler = new WebRequestHandler(); +#else + WinHttpHandler handler = new WinHttpHandler(); +#endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; using (HttpClient client = new HttpClient(handler)) { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index 04a17e4241..da14565de8 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -167,7 +167,7 @@ namespace Microsoft.Net.Http.Server } catch (Exception) { - client.Close(); + ((IDisposable)client).Dispose(); throw; } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index 98f1b28e04..b9423dac99 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -352,7 +352,7 @@ namespace Microsoft.Net.Http.Server } catch (Exception) { - client.Close(); + ((IDisposable)client).Dispose(); throw; } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index 54ad7c54eb..f28e6850a5 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -99,7 +99,7 @@ namespace Microsoft.Net.Http.Server byte[] response = new byte[1024 * 5]; await Task.Run(() => socket.Receive(response)); - socket.Close(); + socket.Dispose(); } } } \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 8cae679baa..95ebe7e7a6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -8,6 +8,7 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server @@ -94,7 +95,7 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(address); var context = await server.GetContextAsync(); - context.Response.Headers["transfeR-Encoding"] = " CHunked "; + context.Response.Headers["transfeR-Encoding"] = "CHunked"; Stream stream = context.Response.Body; var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); await stream.WriteAsync(responseBytes, 0, responseBytes.Length); @@ -121,7 +122,11 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = context.Response.Body; +#if DNX451 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); +#else + await stream.WriteAsync(new byte[10], 0, 10); +#endif stream.Write(new byte[10], 0, 10); await stream.WriteAsync(new byte[10], 0, 10); context.Dispose(); @@ -148,12 +153,12 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); - +#if !DNXCORE50 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); - +#endif await Assert.ThrowsAsync(() => responseTask); } } @@ -170,13 +175,13 @@ namespace Microsoft.Net.Http.Server context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); - +#if !DNXCORE50 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); - +#endif await Assert.ThrowsAsync(() => responseTask); } } @@ -194,14 +199,14 @@ namespace Microsoft.Net.Http.Server context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); - +#if !DNXCORE50 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); - +#endif await Assert.ThrowsAsync(() => responseTask); } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index fca4fd66fc..0d9d9e9638 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -6,9 +6,10 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server.FunctionalTests +namespace Microsoft.Net.Http.Server { public class ResponseCachingTests { @@ -17,7 +18,7 @@ namespace Microsoft.Net.Http.Server.FunctionalTests public ResponseCachingTests() { - _absoluteFilePath = Directory.GetFiles(Environment.CurrentDirectory).First(); + _absoluteFilePath = Directory.GetFiles(Directory.GetCurrentDirectory()).First(); _fileLength = new FileInfo(_absoluteFilePath).Length; } @@ -473,6 +474,12 @@ namespace Microsoft.Net.Http.Server.FunctionalTests // Http.Sys will cache any status code. for (int status = 200; status < 600; status++) { + // 407 (Proxy Authentication Required) makes CoreCLR's HttpClient throw + if (status == 407) + { + continue; + } + var responseTask = SendRequestAsync(address + status); var context = await server.GetContextAsync(); @@ -935,7 +942,8 @@ namespace Microsoft.Net.Http.Server.FunctionalTests } // http://tools.ietf.org/html/rfc7233#section-4.1 - [Fact] + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "Cached response contains duplicate Content-Length headers (#167).")] public async Task Caching_RequestRangeFromCache_RangeServedFromCache() { string address; @@ -956,11 +964,11 @@ namespace Microsoft.Net.Http.Server.FunctionalTests Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); Assert.Equal(new byte[100], await response.Content.ReadAsByteArrayAsync()); - response = await SendRequestAsync(address, "GET", "Range", "bytes=0-10"); + response = await SendRequestAsync(address, "GET", "Range", "bytes=0-10", HttpCompletionOption.ResponseHeadersRead); Assert.Equal(206, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); Assert.Equal("bytes 0-10/100", response.Content.Headers.GetValues("content-range").FirstOrDefault()); - Assert.Equal(new byte[11], await response.Content.ReadAsByteArrayAsync()); + Assert.Equal(11, response.Content.Headers.ContentLength); } } @@ -993,7 +1001,8 @@ namespace Microsoft.Net.Http.Server.FunctionalTests } } - [Fact] + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "Cached response contains duplicate Content-Length headers (#167).")] public async Task Caching_RequestRangeFromCachedFile_ServedFromCache() { string address; @@ -1017,7 +1026,7 @@ namespace Microsoft.Net.Http.Server.FunctionalTests // Send a second request and make sure we get the same response (without listening for one on the server). var rangeLength = responseLength / 2; - response = await SendRequestAsync(address, "GET", "Range", "bytes=0-" + (rangeLength - 1)); + response = await SendRequestAsync(address, "GET", "Range", "bytes=0-" + (rangeLength - 1), HttpCompletionOption.ResponseHeadersRead); Assert.Equal(206, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); Assert.Equal(rangeLength, response.Content.Headers.ContentLength); @@ -1046,26 +1055,28 @@ namespace Microsoft.Net.Http.Server.FunctionalTests Assert.Equal(200, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); Assert.Equal(responseLength, response.Content.Headers.ContentLength); - // Send a second request and make sure we get the same response (without listening for one on the server). var rangeLength = responseLength / 4; - response = await SendRequestAsync(address, "GET", "Range", "bytes=0-" + (rangeLength - 1) + "," + rangeLength + "-" + (rangeLength + rangeLength - 1)); + response = await SendRequestAsync(address, "GET", "Range", "bytes=0-" + (rangeLength - 1) + "," + rangeLength + "-" + (rangeLength + rangeLength - 1), HttpCompletionOption.ResponseHeadersRead); Assert.Equal(206, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); Assert.True(response.Content.Headers.GetValues("content-type").First().StartsWith("multipart/byteranges;")); } } - private async Task SendRequestAsync(string uri, string method = "GET", string extraHeader = null, string extraHeaderValue = null) + private async Task SendRequestAsync(string uri, string method = "GET", string extraHeader = null, string extraHeaderValue = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead) { - using (var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) }) + using (var handler = new HttpClientHandler() { AllowAutoRedirect = false }) { - var request = new HttpRequestMessage(new HttpMethod(method), uri); - if (!string.IsNullOrEmpty(extraHeader)) + using (var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(5) }) { - request.Headers.Add(extraHeader, extraHeaderValue); + var request = new HttpRequestMessage(new HttpMethod(method), uri); + if (!string.IsNullOrEmpty(extraHeader)) + { + request.Headers.Add(extraHeader, extraHeaderValue); + } + return await client.SendAsync(request, httpCompletionOption); } - return await client.SendAsync(request); } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index 46c471c607..ffaa2442d6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -192,7 +192,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); - Assert.Equal(new string[] { "custom1" }, response.Headers.GetValues("WWW-Authenticate")); + Assert.Equal("custom1", response.Headers["WWW-Authenticate"]); } } @@ -217,7 +217,11 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); +#if DNXCORE50 // WebHeaderCollection.GetValues() not available in CoreCLR. + Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); +#else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); +#endif } } @@ -242,7 +246,11 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); +#if DNXCORE50 // WebHeaderCollection.GetValues() not available in CoreCLR. + Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); +#else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); +#endif } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index 66014c92db..4428dfc086 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.Net.Http.Server public ResponseSendFileTests() { - AbsoluteFilePath = Directory.GetFiles(Environment.CurrentDirectory).First(); + AbsoluteFilePath = Directory.GetFiles(Directory.GetCurrentDirectory()).First(); RelativeFilePath = Path.GetFileName(AbsoluteFilePath); FileLength = new FileInfo(AbsoluteFilePath).Length; } @@ -205,9 +205,9 @@ namespace Microsoft.Net.Http.Server [Fact] public async Task ResponseSendFile_EmptyFileCountUnspecified_SetsChunkedAndFlushesHeaders() { - var emptyFilePath = Path.Combine(Environment.CurrentDirectory, "zz_" + Guid.NewGuid().ToString() + "EmptyTestFile.txt"); + var emptyFilePath = Path.Combine(Directory.GetCurrentDirectory(), "zz_" + Guid.NewGuid().ToString() + "EmptyTestFile.txt"); var emptyFile = File.Create(emptyFilePath, 1024); - emptyFile.Close(); + emptyFile.Dispose(); string address; using (var server = Utilities.CreateHttpServer(out address)) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 8b9ed10838..a388436b1c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -8,6 +8,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server @@ -122,11 +123,11 @@ namespace Microsoft.Net.Http.Server context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - +#if !DNXCORE50 // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.GetContextAsync(); context.Abort(); - +#endif await Assert.ThrowsAsync(() => responseTask); } } @@ -246,7 +247,6 @@ namespace Microsoft.Net.Http.Server private async Task SendRequestAsync(string uri) { - ServicePointManager.DefaultConnectionLimit = 100; using (HttpClient client = new HttpClient()) { return await client.GetStringAsync(uri); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs index 11a7bb82fb..5b8ed56e53 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.DirectoryServices.ActiveDirectory; using Microsoft.AspNet.Testing.xunit; namespace Microsoft.Net.Http.Server @@ -19,7 +18,9 @@ namespace Microsoft.Net.Http.Server { try { - return !string.IsNullOrEmpty(Domain.GetComputerDomain().Name); +#if DNX451 + return !string.IsNullOrEmpty(System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name); +#endif } catch { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index aba7cd14c8..9e55f02a07 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -15,6 +15,14 @@ "System.Net.Http": "", "System.Net.Http.WebRequest": "" } + }, + "dnxcore50": { + "dependencies": { + "System.Net.Http": "4.0.1-*", + "System.Net.Http.WinHttpHandler": "4.0.0-*", + "System.Net.Requests": "4.0.11-*", + "System.Net.WebSockets.Client": "4.0.0-*" + } } } } From d9e06f8e6ea3b716ddb2d6eb93dbfa5f8c3a1a14 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Wed, 16 Dec 2015 13:31:33 -0800 Subject: [PATCH 287/597] Don't decode forward slashes in request path (#146). --- global.json | 2 +- .../RequestProcessing/Request.cs | 24 +- .../RequestProcessing/RequestUriBuilder.cs | 326 ++---------------- .../RequestTests.cs | 41 +++ .../RequestTests.cs | 56 ++- 5 files changed, 130 insertions(+), 319 deletions(-) diff --git a/global.json b/global.json index 983ba0401e..ec2e704f70 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,3 @@ { - "projects": ["src"] + "projects": ["src", "test"] } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index a38bd82ede..e3d49d2eea 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -109,21 +109,21 @@ namespace Microsoft.Net.Http.Server } UrlPrefix prefix = httpContext.Server.UrlPrefixes.GetPrefix((int)_contextId); - string orriginalPath = RequestPath; + string originalPath = RequestPath; // These paths are both unescaped already. - if (orriginalPath.Length == prefix.Path.Length - 1) + if (originalPath.Length == prefix.Path.Length - 1) { // They matched exactly except for the trailing slash. - _pathBase = orriginalPath; + _pathBase = originalPath; _path = string.Empty; } else { // url: /base/path, prefix: /base/, base: /base, path: /path // url: /, prefix: /, base: , path: / - _pathBase = orriginalPath.Substring(0, prefix.Path.Length - 1); - _path = orriginalPath.Substring(prefix.Path.Length - 1); + _pathBase = originalPath.Substring(0, prefix.Path.Length - 1); + _path = originalPath.Substring(prefix.Path.Length - 1); } int major = memoryBlob.RequestBlob->Version.MajorVersion; @@ -386,21 +386,7 @@ namespace Microsoft.Net.Http.Server { get { return IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; } } - /* - internal Uri RequestUri - { - get - { - if (_requestUri == null) - { - _requestUri = RequestUriBuilder.GetRequestUri( - _rawUrl, RequestScheme, _cookedUrlHost, _cookedUrlPath, _cookedUrlQuery); - } - return _requestUri; - } - } - */ internal string RequestPath { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 971a10bff8..8461ae531a 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -32,64 +32,29 @@ namespace Microsoft.Net.Http.Server // We don't use the cooked URL because http.sys unescapes all percent-encoded values. However, // we also can't just use the raw Uri, since http.sys supports not only Utf-8, but also ANSI/DBCS and // Unicode code points. System.Uri only supports Utf-8. - // The purpose of this class is to convert all ANSI, DBCS, and Unicode code points into percent encoded - // Utf-8 characters. + // The purpose of this class is to decode all UTF-8 percent encoded characters, with the + // exception of %2F ('/'), which is left encoded. internal sealed class RequestUriBuilder { - private static readonly bool UseCookedRequestUrl; private static readonly Encoding Utf8Encoding; - private static readonly Encoding AnsiEncoding; private readonly string _rawUri; - private readonly string _cookedUriScheme; - private readonly string _cookedUriHost; private readonly string _cookedUriPath; - private readonly string _cookedUriQuery; // This field is used to build the final request Uri string from the Uri parts passed to the ctor. private StringBuilder _requestUriString; // The raw path is parsed by looping through all characters from left to right. 'rawOctets' - // is used to store consecutive percent encoded octets as actual byte values: e.g. for path /pa%C3%84th%2F/ - // rawOctets will be set to { 0xC3, 0x84 } when we reach character 't' and it will be { 0x2F } when + // is used to store consecutive percent encoded octets as actual byte values: e.g. for path /pa%C3%84th%20/ + // rawOctets will be set to { 0xC3, 0x84 } when we reach character 't' and it will be { 0x20 } when // we reach the final '/'. I.e. after a sequence of percent encoded octets ends, we use rawOctets as - // input to the encoding and percent encode the resulting string into UTF-8 octets. - // - // When parsing ANSI (Latin 1) encoded path '/pa%C4th/', %C4 will be added to rawOctets and when - // we reach 't', the content of rawOctets { 0xC4 } will be fed into the ANSI encoding. The resulting - // string '�' will be percent encoded into UTF-8 octets and appended to requestUriString. The final - // path will be '/pa%C3%84th/', where '%C3%84' is the UTF-8 percent encoded character '�'. + // input to the encoding and decode them into a string. private List _rawOctets; private string _rawPath; - // Holds the final request Uri. - private Uri _requestUri; - static RequestUriBuilder() { - // TODO: False triggers more detailed/correct parsing, but it's rather slow. - UseCookedRequestUrl = true; // SettingsSectionInternal.Section.HttpListenerUnescapeRequestUrl; Utf8Encoding = new UTF8Encoding(false, true); -#if DOTNET5_4 - AnsiEncoding = Utf8Encoding; -#else - AnsiEncoding = Encoding.GetEncoding(0, new EncoderExceptionFallback(), new DecoderExceptionFallback()); -#endif - } - - private RequestUriBuilder(string rawUri, string cookedUriScheme, string cookedUriHost, - string cookedUriPath, string cookedUriQuery) - { - Debug.Assert(!string.IsNullOrEmpty(rawUri), "Empty raw URL."); - Debug.Assert(!string.IsNullOrEmpty(cookedUriScheme), "Empty cooked URL scheme."); - Debug.Assert(!string.IsNullOrEmpty(cookedUriHost), "Empty cooked URL host."); - Debug.Assert(!string.IsNullOrEmpty(cookedUriPath), "Empty cooked URL path."); - - this._rawUri = rawUri; - this._cookedUriScheme = cookedUriScheme; - this._cookedUriHost = cookedUriHost; - this._cookedUriPath = AddSlashToAsteriskOnlyPath(cookedUriPath); - this._cookedUriQuery = cookedUriQuery ?? string.Empty; } private RequestUriBuilder(string rawUri, string cookedUriPath) @@ -98,10 +63,7 @@ namespace Microsoft.Net.Http.Server Debug.Assert(!string.IsNullOrEmpty(cookedUriPath), "Empty cooked URL path."); this._rawUri = rawUri; - this._cookedUriScheme = string.Empty; - this._cookedUriHost = string.Empty; this._cookedUriPath = AddSlashToAsteriskOnlyPath(cookedUriPath); - this._cookedUriQuery = string.Empty; } private enum ParsingResult @@ -111,48 +73,6 @@ namespace Microsoft.Net.Http.Server EncodingError } - private enum EncodingType - { - Primary, - Secondary - } - - public static Uri GetRequestUri(string rawUri, string cookedUriScheme, string cookedUriHost, - string cookedUriPath, string cookedUriQuery) - { - RequestUriBuilder builder = new RequestUriBuilder(rawUri, - cookedUriScheme, cookedUriHost, cookedUriPath, cookedUriQuery); - - return builder.Build(); - } - - private Uri Build() - { - // if the user enabled the "use raw Uri" setting in section, we'll use the raw - // path rather than the cooked path. - if (UseCookedRequestUrl) - { - // corresponds to pre-4.0 behavior: use the cooked URI. - BuildRequestUriUsingCookedPath(); - - if (_requestUri == null) - { - BuildRequestUriUsingRawPath(); - } - } - else - { - BuildRequestUriUsingRawPath(); - - if (_requestUri == null) - { - BuildRequestUriUsingCookedPath(); - } - } - - return _requestUri; - } - // Process only the path. internal static string GetRequestPath(string rawUri, string cookedUriPath) { @@ -163,11 +83,6 @@ namespace Microsoft.Net.Http.Server private string GetPath() { - if (UseCookedRequestUrl) - { - return _cookedUriPath; - } - // Initialize 'rawPath' only if really needed; i.e. if we build the request Uri from the raw Uri. _rawPath = GetPath(_rawUri); @@ -181,18 +96,10 @@ namespace Microsoft.Net.Http.Server return _rawPath; } - // Try to check the raw path using first the primary encoding (according to http.sys settings); - // if it fails try the secondary encoding. _rawOctets = new List(); _requestUriString = new StringBuilder(); - ParsingResult result = ParseRawPath(GetEncoding(EncodingType.Primary)); - if (result == ParsingResult.EncodingError) - { - _rawOctets = new List(); - _requestUriString = new StringBuilder(); - result = ParseRawPath(GetEncoding(EncodingType.Secondary)); - } - + ParsingResult result = ParseRawPath(Utf8Encoding); + if (result == ParsingResult.Success) { return _requestUriString.ToString(); @@ -202,115 +109,6 @@ namespace Microsoft.Net.Http.Server return _cookedUriPath; } - private void BuildRequestUriUsingCookedPath() - { - bool isValid = Uri.TryCreate(_cookedUriScheme + Constants.SchemeDelimiter + _cookedUriHost + _cookedUriPath + - _cookedUriQuery, UriKind.Absolute, out _requestUri); - - // Creating a Uri from the cooked Uri should really always work: If not, we log at least. - if (!isValid) - { - LogWarning("BuildRequestUriUsingCookedPath", "Unable to create URI: " + _cookedUriScheme + Constants.SchemeDelimiter + - _cookedUriHost + _cookedUriPath + _cookedUriQuery); - } - } - - private void BuildRequestUriUsingRawPath() - { - bool isValid = false; - - // Initialize 'rawPath' only if really needed; i.e. if we build the request Uri from the raw Uri. - _rawPath = GetPath(_rawUri); - - // If HTTP.sys only parses Utf-8, we can safely use the raw path: it must be a valid Utf-8 string. - if (!HttpSysSettings.EnableNonUtf8 || string.IsNullOrEmpty(_rawPath)) - { - string path = _rawPath; - if (string.IsNullOrEmpty(path)) - { - path = "/"; - Debug.Assert(string.IsNullOrEmpty(_cookedUriQuery), - "Query is only allowed if there is a non-empty path. At least '/' path required."); - } - - isValid = Uri.TryCreate(_cookedUriScheme + Constants.SchemeDelimiter + _cookedUriHost + path + _cookedUriQuery, - UriKind.Absolute, out _requestUri); - } - else - { - // Try to check the raw path using first the primary encoding (according to http.sys settings); - // if it fails try the secondary encoding. - ParsingResult result = BuildRequestUriUsingRawPath(GetEncoding(EncodingType.Primary)); - if (result == ParsingResult.EncodingError) - { - Encoding secondaryEncoding = GetEncoding(EncodingType.Secondary); - result = BuildRequestUriUsingRawPath(secondaryEncoding); - } - isValid = (result == ParsingResult.Success) ? true : false; - } - - // Log that we weren't able to create a Uri from the raw string. - if (!isValid) - { - LogWarning("BuildRequestUriUsingRawPath", "Unable to create Uri: " + _cookedUriScheme + Constants.SchemeDelimiter - + _cookedUriHost + _rawPath + _cookedUriQuery); - } - } - - private static Encoding GetEncoding(EncodingType type) - { - Debug.Assert(HttpSysSettings.EnableNonUtf8, - "If 'EnableNonUtf8' is false we shouldn't require an encoding. It's always Utf-8."); - /* This is mucking up the profiler for some reason. - Debug.Assert((type == EncodingType.Primary) || (type == EncodingType.Secondary), - "Unknown 'EncodingType' value: " + type.ToString()); - */ - if (((type == EncodingType.Primary) && (!HttpSysSettings.FavorUtf8)) || - ((type == EncodingType.Secondary) && (HttpSysSettings.FavorUtf8))) - { - return AnsiEncoding; - } - else - { - return Utf8Encoding; - } - } - - private ParsingResult BuildRequestUriUsingRawPath(Encoding encoding) - { - Debug.Assert(encoding != null, "'encoding' must be assigned."); - Debug.Assert(!string.IsNullOrEmpty(_rawPath), "'rawPath' must have at least one character."); - - _rawOctets = new List(); - _requestUriString = new StringBuilder(); - _requestUriString.Append(_cookedUriScheme); - _requestUriString.Append(Constants.SchemeDelimiter); - _requestUriString.Append(_cookedUriHost); - - ParsingResult result = ParseRawPath(encoding); - if (result == ParsingResult.Success) - { - _requestUriString.Append(_cookedUriQuery); - - Debug.Assert(_rawOctets.Count == 0, - "Still raw octets left. They must be added to the result path."); - - if (!Uri.TryCreate(_requestUriString.ToString(), UriKind.Absolute, out _requestUri)) - { - // If we can't create a Uri from the string, this is an invalid string and it doesn't make - // sense to try another encoding. - result = ParsingResult.InvalidString; - } - } - - if (result != ParsingResult.Success) - { - LogWarning("BuildRequestUriUsingRawPath", "Can't convert the raw path: " + _rawPath + " Encoding: " + encoding.WebName); - } - - return result; - } - private ParsingResult ParseRawPath(Encoding encoding) { Debug.Assert(encoding != null, "'encoding' must be assigned."); @@ -323,45 +121,31 @@ namespace Microsoft.Net.Http.Server if (current == '%') { // Assert is enough, since http.sys accepted the request string already. This should never happen. - Debug.Assert(index + 2 < _rawPath.Length, "Expected >=2 characters after '%' (e.g. %2F)"); + Debug.Assert(index + 2 < _rawPath.Length, "Expected at least 2 characters after '%' (e.g. %20)"); - index++; - current = _rawPath[index]; - if (current == 'u' || current == 'U') - { - // We found "%u" which means, we have a Unicode code point of the form "%uXXXX". - Debug.Assert(index + 4 < _rawPath.Length, "Expected >=4 characters after '%u' (e.g. %u0062)"); + // We have a percent encoded octet: %XX + var octetString = _rawPath.Substring(index + 1, 2); - // Decode the content of rawOctets into percent encoded UTF-8 characters and append them - // to requestUriString. - if (!EmptyDecodeAndAppendRawOctetsList(encoding)) - { - return ParsingResult.EncodingError; - } - if (!AppendUnicodeCodePointValuePercentEncoded(_rawPath.Substring(index + 1, 4))) - { - return ParsingResult.InvalidString; - } - index += 5; - } - else + // Leave %2F as is, otherwise add to raw octets list for unescaping + if (octetString == "2F" || octetString == "2f") { - // We found '%', but not followed by 'u', i.e. we have a percent encoded octed: %XX - if (!AddPercentEncodedOctetToRawOctetsList(encoding, _rawPath.Substring(index, 2))) - { - return ParsingResult.InvalidString; - } - index += 2; + _requestUriString.Append('%'); + _requestUriString.Append(octetString); } + else if (!AddPercentEncodedOctetToRawOctetsList(encoding, octetString)) + { + return ParsingResult.InvalidString; + } + + index += 3; } else { - // We found a non-'%' character: decode the content of rawOctets into percent encoded - // UTF-8 characters and append it to the result. - if (!EmptyDecodeAndAppendRawOctetsList(encoding)) + if (!EmptyDecodeAndAppendDecodedOctetsList(encoding)) { return ParsingResult.EncodingError; } + // Append the current character to the result. _requestUriString.Append(current); index++; @@ -370,7 +154,7 @@ namespace Microsoft.Net.Http.Server // if the raw path ends with a sequence of percent encoded octets, make sure those get added to the // result (requestUriString). - if (!EmptyDecodeAndAppendRawOctetsList(encoding)) + if (!EmptyDecodeAndAppendDecodedOctetsList(encoding)) { return ParsingResult.EncodingError; } @@ -378,44 +162,12 @@ namespace Microsoft.Net.Http.Server return ParsingResult.Success; } - private bool AppendUnicodeCodePointValuePercentEncoded(string codePoint) - { - // http.sys only supports %uXXXX (4 hex-digits), even though unicode code points could have up to - // 6 hex digits. Therefore we parse always 4 characters after %u and convert them to an int. - int codePointValue; - if (!int.TryParse(codePoint, NumberStyles.HexNumber, null, out codePointValue)) - { - LogWarning("AppendUnicodeCodePointValuePercentEncoded", "Can't convert code point: " + codePoint); - return false; - } - - string unicodeString = null; - try - { - unicodeString = char.ConvertFromUtf32(codePointValue); - AppendOctetsPercentEncoded(_requestUriString, Utf8Encoding.GetBytes(unicodeString)); - - return true; - } - catch (ArgumentOutOfRangeException) - { - LogWarning("AppendUnicodeCodePointValuePercentEncoded", "Can't convert code point: " + codePoint); - } - catch (EncoderFallbackException e) - { - // If utf8Encoding.GetBytes() fails - LogWarning("AppendUnicodeCodePointValuePercentEncoded", "Can't convert code point: " + unicodeString, e.Message); - } - - return false; - } - private bool AddPercentEncodedOctetToRawOctetsList(Encoding encoding, string escapedCharacter) { byte encodedValue; if (!byte.TryParse(escapedCharacter, NumberStyles.HexNumber, null, out encodedValue)) { - LogWarning("AddPercentEncodedOctetToRawOctetsList", "Can't convert code point: " + escapedCharacter); + LogWarning(nameof(AddPercentEncodedOctetToRawOctetsList), "Can't convert code point: " + escapedCharacter); return false; } @@ -424,7 +176,7 @@ namespace Microsoft.Net.Http.Server return true; } - private bool EmptyDecodeAndAppendRawOctetsList(Encoding encoding) + private bool EmptyDecodeAndAppendDecodedOctetsList(Encoding encoding) { if (_rawOctets.Count == 0) { @@ -436,44 +188,22 @@ namespace Microsoft.Net.Http.Server { // If the encoding can get a string out of the byte array, this is a valid string in the // 'encoding' encoding. - byte[] bytes = _rawOctets.ToArray(); + var bytes = _rawOctets.ToArray(); decodedString = encoding.GetString(bytes, 0, bytes.Length); - if (encoding == Utf8Encoding) - { - AppendOctetsPercentEncoded(_requestUriString, bytes); - } - else - { - AppendOctetsPercentEncoded(_requestUriString, Utf8Encoding.GetBytes(decodedString)); - } - + _requestUriString.Append(decodedString); _rawOctets.Clear(); return true; } catch (DecoderFallbackException e) { - LogWarning("EmptyDecodeAndAppendRawOctetsList", "Can't convert bytes: " + GetOctetsAsString(_rawOctets), e.Message); - } - catch (EncoderFallbackException e) - { - // If utf8Encoding.GetBytes() fails - LogWarning("EmptyDecodeAndAppendRawOctetsList", "Can't convert bytes: " + decodedString, e.Message); + LogWarning(nameof(EmptyDecodeAndAppendDecodedOctetsList), "Can't convert bytes: " + GetOctetsAsString(_rawOctets), e.Message); } return false; } - private static void AppendOctetsPercentEncoded(StringBuilder target, IEnumerable octets) - { - foreach (byte octet in octets) - { - target.Append('%'); - target.Append(octet.ToString("X2", CultureInfo.InvariantCulture)); - } - } - private static string GetOctetsAsString(IEnumerable octets) { StringBuilder octetString = new StringBuilder(); diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index b31e02852a..8227c2da2c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -18,6 +18,7 @@ using System; using System.IO; using System.Net.Http; +using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Hosting.Server; @@ -87,6 +88,7 @@ namespace Microsoft.AspNet.Server.WebListener [InlineData("/basepath/", "/basepath/subpath", "/basepath", "/subpath")] [InlineData("/base path/", "/base%20path/sub path", "/base path", "/sub path")] [InlineData("/base葉path/", "/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] + [InlineData("/basepath/", "/basepath/sub%2Fpath", "/basepath", "/sub%2Fpath")] public async Task Request_PathSplitting(string pathBase, string requestPath, string expectedPathBase, string expectedPath) { string root; @@ -121,6 +123,23 @@ namespace Microsoft.AspNet.Server.WebListener } } + [Fact] + public async Task Request_DoubleEscapingAllowed() + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => + { + var requestInfo = httpContext.Features.Get(); + Assert.Equal("/%2F", requestInfo.Path); + return Task.FromResult(0); + })) + { + var response = await SendSocketRequestAsync(root, "/%252F"); + var responseStatusCode = response.Substring(9); // Skip "HTTP/1.1 " + Assert.Equal("200", responseStatusCode); + } + } + [Theory] // The test server defines these prefixes: "/", "/11", "/2/3", "/2", "/11/2" [InlineData("/", "", "/")] @@ -189,5 +208,27 @@ namespace Microsoft.AspNet.Server.WebListener return await client.GetStringAsync(uri); } } + + private async Task SendSocketRequestAsync(string address, string path) + { + var uri = new Uri(address); + StringBuilder builder = new StringBuilder(); + builder.AppendLine("GET " + path + " HTTP/1.1"); + builder.AppendLine("Connection: close"); + builder.Append("HOST: "); + builder.AppendLine(uri.Authority); + builder.AppendLine(); + + byte[] request = Encoding.ASCII.GetBytes(builder.ToString()); + + using (var socket = new Socket(SocketType.Stream, ProtocolType.Tcp)) + { + socket.Connect(uri.Host, uri.Port); + socket.Send(request); + var response = new byte[12]; + await Task.Run(() => socket.Receive(response)); + return Encoding.ASCII.GetString(response); + } + } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index de9616280b..6416750001 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Net.Http; +using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using Xunit; @@ -54,8 +55,9 @@ namespace Microsoft.Net.Http.Server [InlineData("/basepath/", "/basepath", "/basepath", "")] [InlineData("/basepath/", "/basepath/", "/basepath", "/")] [InlineData("/basepath/", "/basepath/subpath", "/basepath", "/subpath")] - [InlineData("/base path/", "/base%20path/sub path", "/base path", "/sub path")] + [InlineData("/base path/", "/base%20path/sub%20path", "/base path", "/sub path")] [InlineData("/base葉path/", "/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] + [InlineData("/basepath/", "/basepath/sub%2Fpath", "/basepath", "/sub%2Fpath")] public async Task Request_PathSplitting(string pathBase, string requestPath, string expectedPathBase, string expectedPath) { string root; @@ -80,6 +82,36 @@ namespace Microsoft.Net.Http.Server } } + [Theory] + [InlineData("/path%")] + [InlineData("/path%XY")] + [InlineData("/path%F")] + [InlineData("/path with spaces")] + public async Task Request_MalformedPathReturns400StatusCode(string requestPath) + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) + { + var responseTask = SendSocketRequestAsync(root, requestPath); + var contextTask = server.GetContextAsync(); + var response = await responseTask; + var responseStatusCode = response.Substring(9); // Skip "HTTP/1.1 " + Assert.Equal("400", responseStatusCode); + } + } + + [Fact] + public async Task Request_DoubleEscapingAllowed() + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) + { + var responseTask = SendSocketRequestAsync(root, "/%252F"); + var context = await server.GetContextAsync(); + Assert.Equal("/%2F", context.Request.Path); + } + } + [Theory] // The test server defines these prefixes: "/", "/11", "/2/3", "/2", "/11/2" [InlineData("/", "", "/")] @@ -131,5 +163,27 @@ namespace Microsoft.Net.Http.Server return await client.GetStringAsync(uri); } } + + private async Task SendSocketRequestAsync(string address, string path) + { + var uri = new Uri(address); + StringBuilder builder = new StringBuilder(); + builder.AppendLine("GET " + path + " HTTP/1.1"); + builder.AppendLine("Connection: close"); + builder.Append("HOST: "); + builder.AppendLine(uri.Authority); + builder.AppendLine(); + + byte[] request = Encoding.ASCII.GetBytes(builder.ToString()); + + using (var socket = new Socket(SocketType.Stream, ProtocolType.Tcp)) + { + socket.Connect(uri.Host, uri.Port); + socket.Send(request); + var response = new byte[12]; + await Task.Run(() => socket.Receive(response)); + return Encoding.ASCII.GetString(response); + } + } } } From 17615bef8981133f0629cbead7bde678e1a05645 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 31 Dec 2015 14:59:29 -0800 Subject: [PATCH 288/597] React to HttpAbstractions changes --- .../StandardFeatureCollection.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs index b00cfb6bb7..161ea17a4a 100644 --- a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs @@ -98,5 +98,15 @@ namespace Microsoft.AspNet.Server.WebListener } } } + + public TFeature Get() + { + return (TFeature)this[typeof(TFeature)]; + } + + public void Set(TFeature instance) + { + this[typeof(TFeature)] = instance; + } } } From 1b76152b5c7ba0a7f0e544bb3593c3884986b22d Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Wed, 30 Dec 2015 13:46:08 -0800 Subject: [PATCH 289/597] Enable logging in RequestUriBuilder (#169). --- src/Microsoft.Net.Http.Server/LogHelper.cs | 4 ++-- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestUriBuilder.cs | 20 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index da3c22ded3..98b009afa2 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -51,7 +51,7 @@ namespace Microsoft.Net.Http.Server } } - internal static void LogDebug(ILogger logger, string data) + internal static void LogDebug(ILogger logger, string location, string data) { if (logger == null) { @@ -59,7 +59,7 @@ namespace Microsoft.Net.Http.Server } else { - logger.LogDebug(data); + logger.LogDebug(location + "; " + data); } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index e3d49d2eea..67fd440e90 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -391,7 +391,7 @@ namespace Microsoft.Net.Http.Server { get { - return RequestUriBuilder.GetRequestPath(_rawUrl, _cookedUrlPath); + return RequestUriBuilder.GetRequestPath(_rawUrl, _cookedUrlPath, RequestContext.Logger); } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 8461ae531a..26169bfa36 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -26,6 +26,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Text; +using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { @@ -52,18 +53,22 @@ namespace Microsoft.Net.Http.Server private List _rawOctets; private string _rawPath; + private ILogger _logger; + static RequestUriBuilder() { Utf8Encoding = new UTF8Encoding(false, true); } - private RequestUriBuilder(string rawUri, string cookedUriPath) + private RequestUriBuilder(string rawUri, string cookedUriPath, ILogger logger) { Debug.Assert(!string.IsNullOrEmpty(rawUri), "Empty raw URL."); Debug.Assert(!string.IsNullOrEmpty(cookedUriPath), "Empty cooked URL path."); + Debug.Assert(logger != null, "Null logger."); this._rawUri = rawUri; this._cookedUriPath = AddSlashToAsteriskOnlyPath(cookedUriPath); + this._logger = logger; } private enum ParsingResult @@ -74,9 +79,9 @@ namespace Microsoft.Net.Http.Server } // Process only the path. - internal static string GetRequestPath(string rawUri, string cookedUriPath) + internal static string GetRequestPath(string rawUri, string cookedUriPath, ILogger logger) { - RequestUriBuilder builder = new RequestUriBuilder(rawUri, cookedUriPath); + RequestUriBuilder builder = new RequestUriBuilder(rawUri, cookedUriPath, logger); return builder.GetPath(); } @@ -167,7 +172,7 @@ namespace Microsoft.Net.Http.Server byte encodedValue; if (!byte.TryParse(escapedCharacter, NumberStyles.HexNumber, null, out encodedValue)) { - LogWarning(nameof(AddPercentEncodedOctetToRawOctetsList), "Can't convert code point: " + escapedCharacter); + LogHelper.LogDebug(_logger, nameof(AddPercentEncodedOctetToRawOctetsList), "Can't convert code point: " + escapedCharacter); return false; } @@ -198,7 +203,7 @@ namespace Microsoft.Net.Http.Server } catch (DecoderFallbackException e) { - LogWarning(nameof(EmptyDecodeAndAppendDecodedOctetsList), "Can't convert bytes: " + GetOctetsAsString(_rawOctets), e.Message); + LogHelper.LogDebug(_logger, nameof(EmptyDecodeAndAppendDecodedOctetsList), "Can't convert bytes: " + GetOctetsAsString(_rawOctets) + ": " + e.Message); } return false; @@ -307,10 +312,5 @@ namespace Microsoft.Net.Http.Server return path; } - - private void LogWarning(string methodName, string message, params object[] args) - { - // TODO: Verbose log - } } } From d46de605425de9ecfca837cd62fac2b6faf96af0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 5 Jan 2016 16:11:09 -0800 Subject: [PATCH 290/597] Remove dnx451 and dnxcore50 targets. Reduce Hosting dependency. --- samples/TestClient/Program.cs | 6 +++--- src/Microsoft.AspNet.Server.WebListener/project.json | 6 ------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/samples/TestClient/Program.cs b/samples/TestClient/Program.cs index a85e2fc5c4..23c53b8f89 100644 --- a/samples/TestClient/Program.cs +++ b/samples/TestClient/Program.cs @@ -24,14 +24,14 @@ namespace TestClient /* int completionCount = 0; - int itterations = 30000; - for (int i = 0; i < itterations; i++) + int iterations = 30000; + for (int i = 0; i < iterations; i++) { client.GetAsync(Address) .ContinueWith(t => Interlocked.Increment(ref completionCount)); } - while (completionCount < itterations) + while (completionCount < iterations) { Thread.Sleep(10); }*/ diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 8852f2e655..de325e677c 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -11,13 +11,7 @@ "keyFile": "../../tools/Key.snk" }, "frameworks": { - "dnx451": {}, "net451": { }, - "dnxcore50": { - "dependencies": { - "System.Security.Claims": "4.0.1-*" - } - }, "dotnet5.4": { "dependencies": { "System.Security.Claims": "4.0.1-*" From 0f013999555bab185dfd49005b71c0426e0fabfb Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 8 Jan 2016 12:05:36 -0800 Subject: [PATCH 291/597] #123 Default headers to UTF8 --- .../RequestProcessing/HeaderEncoding.cs | 92 ++++--------------- .../RequestProcessing/Response.cs | 15 +-- src/Microsoft.Net.Http.Server/WebListener.cs | 3 +- .../RequestHeaderTests.cs | 34 ++++++- 4 files changed, 52 insertions(+), 92 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs index 9b3726be86..39f658eb7d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs @@ -21,94 +21,34 @@ // // ----------------------------------------------------------------------- -using System; -using System.Collections.Generic; -using System.Linq; using System.Text; namespace Microsoft.Net.Http.Server { - // we use this static class as a helper class to encode/decode HTTP headers. - // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF - // and a byte in the range 0x00-0xFF (which is the range that can hit the network). - // The Latin-1 encoding (ISO-88591-1) (GetEncoding(28591)) works for byte[] to string, but is a little slow. - // It doesn't work for string -> byte[] because of best-fit-mapping problems. internal static class HeaderEncoding { - internal static unsafe string GetString(byte[] bytes, int byteIndex, int byteCount) - { - fixed (byte* pBytes = bytes) - return GetString(pBytes + byteIndex, byteCount); - } + // It should just be ASCII or ANSI, but they break badly with un-expected values. We use UTF-8 because it's the same for + // ASCII, and because some old client would send UTF8 Host headers and expect UTF8 Location responses + // (e.g. IE and HttpWebRequest on intranets). + private static Encoding Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false); internal static unsafe string GetString(sbyte* pBytes, int byteCount) { - return GetString((byte*)pBytes, byteCount); + // net451: return new string(pBytes, 0, byteCount, Encoding); + + var charCount = Encoding.GetCharCount((byte*)pBytes, byteCount); + var chars = new char[charCount]; + fixed (char* pChars = chars) + { + var count = Encoding.GetChars((byte*)pBytes, byteCount, pChars, charCount); + System.Diagnostics.Debug.Assert(count == charCount); + } + return new string(chars); } - internal static unsafe string GetString(byte* pBytes, int byteCount) + internal static byte[] GetBytes(string myString) { - if (byteCount < 1) - { - return string.Empty; - } - - string s = new String('\0', byteCount); - - fixed (char* pStr = s) - { - char* pString = pStr; - while (byteCount >= 8) - { - pString[0] = (char)pBytes[0]; - pString[1] = (char)pBytes[1]; - pString[2] = (char)pBytes[2]; - pString[3] = (char)pBytes[3]; - pString[4] = (char)pBytes[4]; - pString[5] = (char)pBytes[5]; - pString[6] = (char)pBytes[6]; - pString[7] = (char)pBytes[7]; - pString += 8; - pBytes += 8; - byteCount -= 8; - } - for (int i = 0; i < byteCount; i++) - { - pString[i] = (char)pBytes[i]; - } - } - - return s; - } - - internal static int GetByteCount(string myString) - { - return myString.Length; - } - internal static unsafe void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex) - { - if (myString.Length == 0) - { - return; - } - fixed (byte* bufferPointer = bytes) - { - byte* newBufferPointer = bufferPointer + byteIndex; - int finalIndex = charIndex + charCount; - while (charIndex < finalIndex) - { - *newBufferPointer++ = (byte)myString[charIndex++]; - } - } - } - internal static unsafe byte[] GetBytes(string myString) - { - byte[] bytes = new byte[myString.Length]; - if (myString.Length != 0) - { - GetBytes(myString, 0, myString.Length, bytes, 0); - } - return bytes; + return Encoding.GetBytes(myString); } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index a7d00602ce..668ba5ae42 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -401,11 +401,10 @@ namespace Microsoft.Net.Http.Server cachePolicy.SecondsToLive = (uint)Math.Min(cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue); } - byte[] reasonPhraseBytes = new byte[HeaderEncoding.GetByteCount(reasonPhrase)]; + byte[] reasonPhraseBytes = HeaderEncoding.GetBytes(reasonPhrase); fixed (byte* pReasonPhrase = reasonPhraseBytes) { _nativeResponse.Response_V1.ReasonLength = (ushort)reasonPhraseBytes.Length; - HeaderEncoding.GetBytes(reasonPhrase, 0, reasonPhraseBytes.Length, reasonPhraseBytes, 0); _nativeResponse.Response_V1.pReason = (sbyte*)pReasonPhrase; fixed (HttpApi.HTTP_RESPONSE_V2* pResponse = &_nativeResponse) { @@ -622,18 +621,16 @@ namespace Microsoft.Net.Http.Server for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Name - bytes = new byte[HeaderEncoding.GetByteCount(headerName)]; + bytes = HeaderEncoding.GetBytes(headerName); unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].NameLength = (ushort)bytes.Length; - HeaderEncoding.GetBytes(headerName, 0, bytes.Length, bytes, 0); gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pName = (sbyte*)gcHandle.AddrOfPinnedObject(); // Add Value headerValue = headerValues[headerValueIndex] ?? string.Empty; - bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + bytes = HeaderEncoding.GetBytes(headerValue); unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length; - HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); @@ -643,9 +640,8 @@ namespace Microsoft.Net.Http.Server else if (headerPair.Value.Count == 1) { headerValue = headerValues[0] ?? string.Empty; - bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + bytes = HeaderEncoding.GetBytes(headerValue); pKnownHeaders[lookup].RawValueLength = (ushort)bytes.Length; - HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); pKnownHeaders[lookup].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); @@ -677,9 +673,8 @@ namespace Microsoft.Net.Http.Server { // Add Value headerValue = headerValues[headerValueIndex] ?? string.Empty; - bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + bytes = HeaderEncoding.GetBytes(headerValue); nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; - HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); nativeHeaderValues[header.KnownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 29ecb64eba..942cc18c8f 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -774,9 +774,8 @@ namespace Microsoft.Net.Http.Server { // Add Value string headerValue = authChallenges[headerValueIndex]; - byte[] bytes = new byte[HeaderEncoding.GetByteCount(headerValue)]; + byte[] bytes = HeaderEncoding.GetBytes(headerValue); nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; - HeaderEncoding.GetBytes(headerValue, 0, bytes.Length, bytes, 0); gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); nativeHeaderValues[header.KnownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index f28e6850a5..40980cfbd3 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -1,7 +1,6 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; -using System.Linq; using System.Net.Http; using System.Net.Sockets; using System.Text; @@ -64,7 +63,34 @@ namespace Microsoft.Net.Http.Server await responseTask; } } - + + [Fact] + public async Task RequestHeaders_ClientSendsUtf8Headers_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + string[] customValues = new string[] { "custom1, and custom测试2", "custom3" }; + Task responseTask = SendRequestAsync(address, "Custom-Header", customValues); + + var context = await server.GetContextAsync(); + var requestHeaders = context.Request.Headers; + Assert.Equal(4, requestHeaders.Count); + Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); + Assert.Equal(new[] { new Uri(address).Authority }, requestHeaders.GetValues("Host")); + Assert.Equal("close", requestHeaders["Connection"]); + Assert.Equal(new[] { "close" }, requestHeaders.GetValues("Connection")); + // Apparently Http.Sys squashes request headers together. + Assert.Equal("custom1, and custom测试2, custom3", requestHeaders["Custom-Header"]); + Assert.Equal(new[] { "custom1", "and custom测试2", "custom3" }, requestHeaders.GetValues("Custom-Header")); + Assert.Equal("spacervalue, spacervalue", requestHeaders["Spacer-Header"]); + Assert.Equal(new[] { "spacervalue", "spacervalue" }, requestHeaders.GetValues("Spacer-Header")); + context.Dispose(); + + await responseTask; + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) @@ -90,7 +116,7 @@ namespace Microsoft.Net.Http.Server } builder.AppendLine(); - byte[] request = Encoding.ASCII.GetBytes(builder.ToString()); + byte[] request = Encoding.UTF8.GetBytes(builder.ToString()); Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); socket.Connect(uri.Host, uri.Port); From 6e67f78ed08c55278f401a79b207608b8949fafc Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Mon, 11 Jan 2016 14:27:53 -0800 Subject: [PATCH 292/597] Build with dotnet --- .gitattributes | 1 + .gitignore | 4 +- .travis.yml | 8 ++- appveyor.yml | 2 +- build.cmd | 68 +++++++++---------- build.sh | 47 +++++++------ makefile.shade | 7 -- .../project.json | 44 ++++++------ .../project.json | 7 +- 9 files changed, 100 insertions(+), 88 deletions(-) delete mode 100644 makefile.shade diff --git a/.gitattributes b/.gitattributes index bdaa5ba982..97b827b758 100644 --- a/.gitattributes +++ b/.gitattributes @@ -48,3 +48,4 @@ *.fsproj text=auto *.dbproj text=auto *.sln text=auto eol=crlf +*.sh eol=lf diff --git a/.gitignore b/.gitignore index 2f2c21bf2e..c9c2ae767f 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ nuget.exe *.ipch *.sln.ide project.lock.json -/.vs \ No newline at end of file +/.vs +.build/ +.testPublish/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 2fc624899f..bf811dc26a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,11 @@ addons: - libssl-dev - libunwind8 - zlib1g -env: - - KOREBUILD_DNU_RESTORE_CORECLR=true mono: - 4.0.5 +os: + - linux + - osx +osx_image: xcode7.1 script: - - ./build.sh --quiet verify + - ./build.sh verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 636a7618d3..3fab83e134 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ init: - git config --global core.autocrlf true build_script: - - build.cmd --quiet verify + - build.cmd verify clone_depth: 1 test: off deploy: off \ No newline at end of file diff --git a/build.cmd b/build.cmd index 553e3929a0..ebb619e737 100644 --- a/build.cmd +++ b/build.cmd @@ -1,40 +1,40 @@ -@echo off -cd %~dp0 - +@ECHO off SETLOCAL + +SET REPO_FOLDER=%~dp0 +CD %REPO_FOLDER% + +SET BUILD_FOLDER=.build +SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet +SET KOREBUILD_VERSION= + +SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe SET NUGET_VERSION=latest SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe -SET BUILDCMD_KOREBUILD_VERSION= -SET BUILDCMD_DNX_VERSION= -IF EXIST %CACHED_NUGET% goto copynuget -echo Downloading latest version of NuGet.exe... -IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet -@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - -:copynuget -IF EXIST .nuget\nuget.exe goto restore -md .nuget -copy %CACHED_NUGET% .nuget\nuget.exe > nul - -:restore -IF EXIST packages\Sake goto getdnx -IF "%BUILDCMD_KOREBUILD_VERSION%"=="" ( - .nuget\nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre -) ELSE ( - .nuget\nuget.exe install KoreBuild -version %BUILDCMD_KOREBUILD_VERSION% -ExcludeVersion -o packages -nocache -pre -) -.nuget\NuGet.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages - -:getdnx -IF "%BUILDCMD_DNX_VERSION%"=="" ( - SET BUILDCMD_DNX_VERSION=latest -) -IF "%SKIP_DNX_INSTALL%"=="" ( - CALL packages\KoreBuild\build\dnvm install %BUILDCMD_DNX_VERSION% -runtime CoreCLR -arch x86 -alias default - CALL packages\KoreBuild\build\dnvm install default -runtime CLR -arch x86 -alias default -) ELSE ( - CALL packages\KoreBuild\build\dnvm use default -runtime CLR -arch x86 +IF NOT EXIST %BUILD_FOLDER% ( + md %BUILD_FOLDER% ) -packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %* +IF NOT EXIST %NUGET_PATH% ( + IF NOT EXIST %CACHED_NUGET% ( + echo Downloading latest version of NuGet.exe... + IF NOT EXIST %LocalAppData%\NuGet ( + md %LocalAppData%\NuGet + ) + @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" + ) + + copy %CACHED_NUGET% %NUGET_PATH% > nul +) + +IF NOT EXIST %KOREBUILD_FOLDER% ( + SET KOREBUILD_DOWNLOAD_ARGS= + IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% + ) + + %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% +) + +"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* diff --git a/build.sh b/build.sh index da4e3fcd1c..7b5e25e3a8 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,18 @@ #!/usr/bin/env bash +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +repoFolder="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +buildFolder=.build +koreBuildFolder=$buildFolder/KoreBuild-dotnet + +nugetPath=$buildFolder/nuget.exe + if test `uname` = Darwin; then cachedir=~/Library/Caches/KBuild else @@ -11,33 +24,25 @@ else fi mkdir -p $cachedir nugetVersion=latest -cachePath=$cachedir/nuget.$nugetVersion.exe +cacheNuget=$cachedir/nuget.$nugetVersion.exe -url=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe -if test ! -f $cachePath; then - wget -O $cachePath $url 2>/dev/null || curl -o $cachePath --location $url /dev/null +if test ! -d $buildFolder; then + mkdir $buildFolder fi -if test ! -e .nuget; then - mkdir .nuget - cp $cachePath .nuget/nuget.exe +if test ! -f $nugetPath; then + if test ! -f $cacheNuget; then + wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + fi + + cp $cacheNuget $nugetPath fi -if test ! -d packages/Sake; then - mono .nuget/nuget.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre - mono .nuget/nuget.exe install Sake -ExcludeVersion -Source https://www.nuget.org/api/v2/ -Out packages +if test ! -d $koreBuildFolder; then + mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre fi -if ! type dnvm > /dev/null 2>&1; then - source packages/KoreBuild/build/dnvm.sh -fi +source $koreBuildFolder/build/KoreBuild.sh -if ! type dnx > /dev/null 2>&1 || [ -z "$SKIP_DNX_INSTALL" ]; then - dnvm install latest -runtime coreclr -alias default - dnvm install default -runtime mono -alias default -else - dnvm use default -runtime mono -fi - -mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@" diff --git a/makefile.shade b/makefile.shade deleted file mode 100644 index 562494d144..0000000000 --- a/makefile.shade +++ /dev/null @@ -1,7 +0,0 @@ - -var VERSION='0.1' -var FULL_VERSION='0.1' -var AUTHORS='Microsoft Open Technologies, Inc.' - -use-standard-lifecycle -k-standard-goals diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json index 9fee80e2f2..39978ebf9c 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json @@ -1,25 +1,29 @@ { - "commands": { - "test": "xunit.runner.aspnet" + "testRunner": "xunit", + "commands": { + "test": "xunit.runner.aspnet" + }, + "dependencies": { + "Microsoft.AspNet.Server.WebListener": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*" + }, + "frameworks": { + "dnx451": { + "frameworkAssemblies": { + "System.Net.Http": "", + "System.Net.Http.WebRequest": "" + }, + "dependencies": { + "xunit.runner.console": "2.1.0" + } }, - "dependencies": { - "Microsoft.AspNet.Server.WebListener": "1.0.0-*", - "Microsoft.AspNet.Testing": "1.0.0-*", + "dnxcore50": { + "dependencies": { + "System.Net.Http.WinHttpHandler": "4.0.0-*", + "System.Net.Requests": "4.0.11-*", + "System.Net.WebHeaderCollection": "4.0.1-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "frameworks": { - "dnx451": { - "frameworkAssemblies": { - "System.Net.Http": "", - "System.Net.Http.WebRequest": "" - } - }, - "dnxcore50": { - "dependencies": { - "System.Net.Http.WinHttpHandler": "4.0.0-*", - "System.Net.Requests": "4.0.11-*", - "System.Net.WebHeaderCollection": "4.0.1-*" - } - } + } } + } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 9e55f02a07..017ab2aa10 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,4 +1,5 @@ { + "testRunner": "xunit", "commands": { "test": "xunit.runner.aspnet" }, @@ -14,6 +15,9 @@ "System.DirectoryServices": "", "System.Net.Http": "", "System.Net.Http.WebRequest": "" + }, + "dependencies": { + "xunit.runner.console": "2.1.0" } }, "dnxcore50": { @@ -21,7 +25,8 @@ "System.Net.Http": "4.0.1-*", "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", - "System.Net.WebSockets.Client": "4.0.0-*" + "System.Net.WebSockets.Client": "4.0.0-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" } } } From 82929103f055c36f731dda3714b57ab8147755cd Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 14 Jan 2016 16:41:15 -0800 Subject: [PATCH 293/597] Updating build script --- build.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/build.sh b/build.sh index 7b5e25e3a8..263fb667a8 100755 --- a/build.sh +++ b/build.sh @@ -1,13 +1,5 @@ #!/usr/bin/env bash -SOURCE="${BASH_SOURCE[0]}" -while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located -done -repoFolder="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - buildFolder=.build koreBuildFolder=$buildFolder/KoreBuild-dotnet @@ -42,7 +34,12 @@ fi if test ! -d $koreBuildFolder; then mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre + chmod +x $koreBuildFolder/build/KoreBuild.sh fi -source $koreBuildFolder/build/KoreBuild.sh +makeFile=makefile.shade +if [ ! -e $makeFile ]; then + makeFile=$koreBuildFolder/build/makefile.shade +fi +./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" From 8ff779778c92bd8d00c54182f44da25a630cc0b8 Mon Sep 17 00:00:00 2001 From: John Luo Date: Sun, 17 Jan 2016 15:58:30 -0800 Subject: [PATCH 294/597] Reacting to hosting rename --- samples/HotAddSample/Startup.cs | 6 +++--- samples/SelfHostServer/Startup.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index 6da3251b00..aff6a0de15 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -90,12 +90,12 @@ namespace HotAddSample public static void Main(string[] args) { - var application = new WebApplicationBuilder() - .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + var host = new WebHostBuilder() + .UseDefaultConfiguration(args) .UseStartup() .Build(); - application.Run(); + host.Run(); } } } diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 377cc3eb63..73eac09160 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -40,12 +40,12 @@ namespace SelfHostServer public static void Main(string[] args) { - var application = new WebApplicationBuilder() - .UseConfiguration(WebApplicationConfiguration.GetDefault(args)) + var host = new WebHostBuilder() + .UseDefaultConfiguration(args) .UseStartup() .Build(); - application.Run(); + host.Run(); } } } From 1cae0695f72d1e00d8e4d7bf8268cbdee4f56e23 Mon Sep 17 00:00:00 2001 From: Brennan Date: Tue, 19 Jan 2016 08:50:17 -0800 Subject: [PATCH 295/597] Remove IsLocal --- samples/HelloWorld/Program.cs | 1 - .../FeatureContext.cs | 14 -------------- .../RequestProcessing/Request.cs | 8 -------- .../RequestTests.cs | 1 - .../RequestTests.cs | 1 - 5 files changed, 25 deletions(-) diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 2f62f082fe..7b545803e9 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -30,7 +30,6 @@ namespace HelloWorld // Request // context.Request.ProtocolVersion - // context.Request.IsLocal // context.Request.Headers // context.Request.Method // context.Request.Body diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs index e311ebf82b..a74869fe13 100644 --- a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs @@ -65,7 +65,6 @@ namespace Microsoft.AspNet.Server.WebListener private IPAddress _localIpAddress; private int? _remotePort; private int? _localPort; - private bool? _isLocal; private string _requestId; private X509Certificate2 _clientCert; private ClaimsPrincipal _user; @@ -219,19 +218,6 @@ namespace Microsoft.AspNet.Server.WebListener set { _scheme = value; } } - bool IHttpConnectionFeature.IsLocal - { - get - { - if (_isLocal == null) - { - _isLocal = Request.IsLocal; - } - return _isLocal.Value; - } - set { _isLocal = value; } - } - IPAddress IHttpConnectionFeature.LocalIpAddress { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 67fd440e90..5ffebdfb8b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -294,14 +294,6 @@ namespace Microsoft.Net.Http.Server get { return _path; } } - public bool IsLocal - { - get - { - return LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress()); - } - } - public bool IsSecureConnection { get diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs index 8227c2da2c..167771032e 100644 --- a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs @@ -59,7 +59,6 @@ namespace Microsoft.AspNet.Server.WebListener Assert.NotEqual(0, connectionInfo.RemotePort); Assert.Equal("::1", connectionInfo.LocalIpAddress.ToString()); Assert.NotEqual(0, connectionInfo.LocalPort); - Assert.True(connectionInfo.IsLocal); // Trace identifier var requestIdentifierFeature = httpContext.Features.Get(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index 6416750001..ac7b14d0c6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -39,7 +39,6 @@ namespace Microsoft.Net.Http.Server Assert.NotEqual(0, request.RemotePort); Assert.Equal("::1", request.LocalIpAddress.ToString()); Assert.NotEqual(0, request.LocalPort); - Assert.True(request.IsLocal); // Note: Response keys are validated in the ResponseTests From f368edc02877fb39352c1993f0d590032f827931 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 20 Jan 2016 21:01:39 -0800 Subject: [PATCH 296/597] Reacting to CoreCLR package version change --- samples/HelloWorld/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- src/Microsoft.Net.WebSockets.Server/project.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 8f8d2299aa..6ba641c8c9 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -13,7 +13,7 @@ "System.Collections": "4.0.11-*", "System.Console": "4.0.0-*", "System.Globalization": "4.0.11-*", - "System.IO": "4.0.11-*", + "System.IO": "4.1.0-*", "System.Runtime": "4.0.21-*", "System.Threading.Tasks": "4.0.11-*" } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index f67b5bac6c..f314ae21aa 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -17,7 +17,7 @@ "System.Diagnostics.Contracts": "4.0.1-*", "System.Diagnostics.Debug": "4.0.11-*", "System.Diagnostics.Tools": "4.0.1-*", - "System.IO": "4.0.11-*", + "System.IO": "4.1.0-*", "System.IO.FileSystem": "4.0.1-*", "System.Net.Primitives": "4.0.11-*", "System.Runtime.InteropServices": "4.0.21-*", diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 140c3637b5..50925126d7 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -16,7 +16,7 @@ "System.Linq": "4.0.1-*", "System.Net.WebSockets": "4.0.0-*", "System.Resources.ResourceManager": "4.0.1-*", - "System.Runtime.Extensions": "4.0.11-*", + "System.Runtime.Extensions": "4.1.0-*", "System.Security.Cryptography.Algorithms": "4.0.0-*", "System.Threading": "4.0.11-*", "System.Threading.Tasks": "4.0.11-*", From 295c98c757aa2c1d1c3d75dd19cfe53df226a50b Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:23:31 -0800 Subject: [PATCH 297/597] Rename AspNet 5 folders and files. See https://github.com/aspnet/Announcements/issues/144 for more information. --- .../AuthenticationHandler.cs | 0 .../FeatureContext.cs | 0 .../HeaderDictionary.cs | 0 .../Helpers.cs | 0 .../LogHelper.cs | 0 .../MessagePump.cs | 0 .../Microsoft.AspNetCore.Server.WebListener.xproj} | 0 .../Properties/AssemblyInfo.cs | 0 .../ServerAddressesFeature.cs | 0 .../ServerFactory.cs | 0 .../StandardFeatureCollection.cs | 0 .../project.json | 0 .../AuthenticationTests.cs | 0 .../DummyApplication.cs | 0 .../HttpsTests.cs | 0 ...Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj} | 0 .../OpaqueUpgradeTests.cs | 0 .../RequestBodyTests.cs | 0 .../RequestHeaderTests.cs | 0 .../RequestTests.cs | 0 .../ResponseBodyTests.cs | 0 .../ResponseCachingTests.cs | 0 .../ResponseHeaderTests.cs | 0 .../ResponseSendFileTests.cs | 0 .../ResponseTests.cs | 0 .../ServerTests.cs | 0 .../Utilities.cs | 0 .../WebSocketTests.cs | 0 .../project.json | 0 29 files changed, 0 insertions(+), 0 deletions(-) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/AuthenticationHandler.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/FeatureContext.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/HeaderDictionary.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/Helpers.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/LogHelper.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/MessagePump.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj => Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj} (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/Properties/AssemblyInfo.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/ServerAddressesFeature.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/ServerFactory.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/StandardFeatureCollection.cs (100%) rename src/{Microsoft.AspNet.Server.WebListener => Microsoft.AspNetCore.Server.WebListener}/project.json (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/AuthenticationTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/DummyApplication.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/HttpsTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj => Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj} (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/OpaqueUpgradeTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/RequestBodyTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/RequestHeaderTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/RequestTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/ResponseBodyTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/ResponseCachingTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/ResponseHeaderTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/ResponseSendFileTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/ResponseTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/ServerTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/Utilities.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/WebSocketTests.cs (100%) rename test/{Microsoft.AspNet.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.WebListener.FunctionalTests}/project.json (100%) diff --git a/src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/AuthenticationHandler.cs rename to src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/FeatureContext.cs rename to src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/HeaderDictionary.cs b/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/HeaderDictionary.cs rename to src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/Helpers.cs b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/Helpers.cs rename to src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/LogHelper.cs rename to src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/MessagePump.cs rename to src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj b/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/Microsoft.AspNet.Server.WebListener.xproj rename to src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj diff --git a/src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/Properties/AssemblyInfo.cs rename to src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerAddressesFeature.cs b/src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/ServerAddressesFeature.cs rename to src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/ServerFactory.cs rename to src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/StandardFeatureCollection.cs rename to src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json similarity index 100% rename from src/Microsoft.AspNet.Server.WebListener/project.json rename to src/Microsoft.AspNetCore.Server.WebListener/project.json diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/AuthenticationTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/DummyApplication.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/DummyApplication.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/HttpsTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestBodyTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestHeaderTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/RequestTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseBodyTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseCachingTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ResponseTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/ServerTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/Utilities.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/WebSocketTests.cs rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs diff --git a/test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json similarity index 100% rename from test/Microsoft.AspNet.Server.WebListener.FunctionalTests/project.json rename to test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json From a83445441ad409e96c9443a084bd99a04b5f3bbd Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:23:36 -0800 Subject: [PATCH 298/597] Rename AspNet 5 file contents. See https://github.com/aspnet/Announcements/issues/144 for more information. --- NuGetPackageVerifier.json | 2 +- WebListener.sln | 6 +++--- samples/HotAddSample/Startup.cs | 10 +++++----- samples/HotAddSample/hosting.json | 4 ++-- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/Startup.cs | 8 ++++---- samples/SelfHostServer/hosting.json | 4 ++-- samples/SelfHostServer/project.json | 2 +- .../AuthenticationHandler.cs | 6 +++--- .../FeatureContext.cs | 8 ++++---- .../HeaderDictionary.cs | 6 +++--- .../Helpers.cs | 2 +- .../LogHelper.cs | 2 +- .../MessagePump.cs | 8 ++++---- .../ServerAddressesFeature.cs | 6 +++--- .../ServerFactory.cs | 8 ++++---- .../StandardFeatureCollection.cs | 6 +++--- .../project.json | 2 +- .../Legacy/WebSocketHttpListenerDuplexStream.cs | 2 +- .../AuthenticationTests.cs | 6 +++--- .../DummyApplication.cs | 12 ++++++------ .../HttpsTests.cs | 4 ++-- .../OpaqueUpgradeTests.cs | 8 ++++---- .../RequestBodyTests.cs | 8 ++++---- .../RequestHeaderTests.cs | 6 +++--- .../RequestTests.cs | 10 +++++----- .../ResponseBodyTests.cs | 8 ++++---- .../ResponseCachingTests.cs | 8 ++++---- .../ResponseHeaderTests.cs | 4 ++-- .../ResponseSendFileTests.cs | 4 ++-- .../ResponseTests.cs | 6 +++--- .../ServerTests.cs | 6 +++--- .../Utilities.cs | 12 ++++++------ .../WebSocketTests.cs | 8 ++++---- .../project.json | 4 ++-- .../AuthenticationTests.cs | 4 ++-- .../OpaqueUpgradeTests.cs | 4 ++-- .../ResponseBodyTests.cs | 4 ++-- .../ResponseCachingTests.cs | 4 ++-- .../ServerTests.cs | 4 ++-- .../SkipOffDomainAttribute.cs | 2 +- .../Utilities.cs | 4 ++-- .../WebSocketTests.cs | 4 ++-- .../project.json | 2 +- 44 files changed, 120 insertions(+), 120 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 3c2d007f30..e087c17fa1 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -9,7 +9,7 @@ "StrictSemanticVersionValidationRule" ], "packages": { - "Microsoft.AspNet.Server.WebListener": { }, + "Microsoft.AspNetCore.Server.WebListener": { }, "Microsoft.Net.Http.Server": { }, "Microsoft.Net.WebSockets.Server": { } } diff --git a/WebListener.sln b/WebListener.sln index 618e975e97..5570995d52 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.23107.0 @@ -19,9 +19,9 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\S EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.WebSockets.Server", "src\Microsoft.Net.WebSockets.Server\Microsoft.Net.WebSockets.Server.xproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener.FunctionalTests", "test\Microsoft.AspNet.Server.WebListener.FunctionalTests\Microsoft.AspNet.Server.WebListener.FunctionalTests.xproj", "{4492FF4C-9032-411D-853F-46B01755E504}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.WebListener.FunctionalTests", "test\Microsoft.AspNetCore.Server.WebListener.FunctionalTests\Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj", "{4492FF4C-9032-411D-853F-46B01755E504}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Server.WebListener", "src\Microsoft.AspNet.Server.WebListener\Microsoft.AspNet.Server.WebListener.xproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.WebListener", "src\Microsoft.AspNetCore.Server.WebListener\Microsoft.AspNetCore.Server.WebListener.xproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server.FunctionalTests", "test\Microsoft.Net.Http.Server.FunctionalTests\Microsoft.Net.Http.Server.FunctionalTests.xproj", "{DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}" EndProject diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index aff6a0de15..d2ef0cbfd0 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -1,9 +1,9 @@ using System; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Server.Features; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Server.Features; using Microsoft.Extensions.Logging; namespace HotAddSample diff --git a/samples/HotAddSample/hosting.json b/samples/HotAddSample/hosting.json index 2efa8f78a3..598af3d3a8 100644 --- a/samples/HotAddSample/hosting.json +++ b/samples/HotAddSample/hosting.json @@ -1,4 +1,4 @@ -{ - "server": "Microsoft.AspNet.Server.WebListener", +{ + "server": "Microsoft.AspNetCore.Server.WebListener", "server.urls": "http://localhost:12345" } diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 4b5d9cf38d..22f851418f 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,7 +1,7 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNet.Server.WebListener": "1.0.0-*", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "compilationOptions": { diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 73eac09160..9ee6194f07 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -2,10 +2,10 @@ using System; using System.Net.WebSockets; using System.Text; using System.Threading; -using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Hosting; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; diff --git a/samples/SelfHostServer/hosting.json b/samples/SelfHostServer/hosting.json index 6ac58d83c9..c1733ee469 100644 --- a/samples/SelfHostServer/hosting.json +++ b/samples/SelfHostServer/hosting.json @@ -1,4 +1,4 @@ -{ - "server": "Microsoft.AspNet.Server.WebListener", +{ + "server": "Microsoft.AspNetCore.Server.WebListener", "server.urls": "http://localhost:8080" } diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index d0e19d44c0..8fd986fded 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNet.Server.WebListener": "1.0.0-*", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "compilationOptions": { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs index 458e5a2009..b1f9aec312 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,10 +25,10 @@ using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Net.Http.Server; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal class AuthenticationHandler : IAuthenticationHandler { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index a74869fe13..4068da2818 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -23,13 +23,13 @@ using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Server; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal class FeatureContext : IHttpRequestFeature, diff --git a/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs b/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs index 7c78b196f7..b71a1bd876 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs @@ -4,10 +4,10 @@ using System; using System.Collections; using System.Collections.Generic; -using Microsoft.AspNet.Http; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { /// /// Represents a wrapper for RequestHeaders and ResponseHeaders. @@ -144,7 +144,7 @@ namespace Microsoft.AspNet.Server.WebListener /// /// Copies the elements to a one-dimensional Array instance at the specified index. /// - /// The one-dimensional Array that is the destination of the specified objects copied from the . + /// The one-dimensional Array that is the destination of the specified objects copied from the . /// The zero-based index in at which copying begins. public void CopyTo(KeyValuePair[] array, int arrayIndex) { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs index 4520aa2adf..f9ff181782 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs @@ -24,7 +24,7 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal static class Helpers { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs index 5db901b922..a2ee73f12e 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs @@ -25,7 +25,7 @@ using System; using System.Diagnostics; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal static class LogHelper { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs index 9cb66bc7ba..cb2bca862d 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs @@ -20,13 +20,13 @@ using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Server.Features; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Server.Features; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal class MessagePump : IServer { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs b/src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs index d617baa7ea..f7ca6cc178 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,9 +16,9 @@ // permissions and limitations under the License. using System.Collections.Generic; -using Microsoft.AspNet.Server.Features; +using Microsoft.AspNetCore.Server.Features; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal class ServerAddressesFeature : IServerAddressesFeature { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs index 1e72371d8a..b37bfb7dd8 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs @@ -36,13 +36,13 @@ using System; using System.Diagnostics.CodeAnalysis; -using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Server.Features; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Server.Features; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { /// /// Implements the setup process for this server. diff --git a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs index 161ea17a4a..eccf7418e5 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs @@ -18,11 +18,11 @@ using System; using System.Collections; using System.Collections.Generic; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Net.Http.Server; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal sealed class StandardFeatureCollection : IFeatureCollection { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index de325e677c..44917648c5 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -2,7 +2,7 @@ "version": "1.0.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { - "Microsoft.AspNet.Hosting": "1.0.0-*", + "Microsoft.AspNetCore.Hosting": "1.0.0-*", "Microsoft.Net.Http.Headers": "1.0.0-*", "Microsoft.Net.Http.Server": "1.0.0-*" }, diff --git a/src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs b/src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs index 1e23d2ec6e..be72c5f88e 100644 --- a/src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs +++ b/src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ /* -namespace Microsoft.AspNet.WebSockets +namespace Microsoft.AspNetCore.WebSockets { using Microsoft.Net; using System; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 2b5d570844..7606cc1bc9 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -20,12 +20,12 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features.Authentication; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class AuthenticationTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs index 21c4aed52f..a8863fbaf2 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,12 +17,12 @@ using System; using System.Threading.Tasks; -using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Internal; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal class DummyApplication : IHttpApplication { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs index 3027f4bc70..7616dc5392 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -21,10 +21,10 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Http.Features; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class HttpsTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 0db487cd09..191208da1e 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -22,12 +22,12 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class OpaqueUpgradeTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 58a1de5318..f11949a4e7 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,11 +23,11 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Internal; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class RequestBodyTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index 62f7a36708..d6da222f14 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -20,12 +20,12 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Internal; using Microsoft.Extensions.Primitives; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class RequestHeaderTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index 167771032e..6f57582cb9 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,13 +21,13 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.Net.Http.Server; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class RequestTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 68a214cc83..42224e5df3 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -23,12 +23,12 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class ResponseBodyTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index 0c713606f8..70b44128e3 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -1,14 +1,14 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Linq; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Internal; using Xunit; -namespace Microsoft.AspNet.Server.WebListener.FunctionalTests +namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests { public class ResponseCachingTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 65cc7ba379..4ec53b2a36 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -22,11 +22,11 @@ using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Primitives; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class ResponseHeaderTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 48ef151349..3c39c77764 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -24,10 +24,10 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Http.Features; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class ResponseSendFileTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs index 516b2dc87f..ad63957536 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -19,11 +19,11 @@ using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Internal; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class ResponseTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs index 15ca0a7754..37660b5380 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs @@ -24,12 +24,12 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; using Microsoft.Net.Http.Server; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class ServerTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs index 597f9aaf32..97521f74bd 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs @@ -16,14 +16,14 @@ // permissions and limitations under the License. using System; -using Microsoft.AspNet.Hosting.Server; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Http.Internal; -using Microsoft.AspNet.Server.Features; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.AspNetCore.Server.Features; using Microsoft.Net.Http.Server; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { internal static class Utilities { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs index c39ae4b1d8..c34936f454 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -20,12 +20,12 @@ using System.Net.Http; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNet.Server.WebListener +namespace Microsoft.AspNetCore.Server.WebListener { public class WebSocketTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 39978ebf9c..68da4685aa 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -4,8 +4,8 @@ "test": "xunit.runner.aspnet" }, "dependencies": { - "Microsoft.AspNet.Server.WebListener": "1.0.0-*", - "Microsoft.AspNet.Testing": "1.0.0-*" + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-*", + "Microsoft.AspNetCore.Testing": "1.0.0-*" }, "frameworks": { "dnx451": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 8281eb53fa..2721e6cab1 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index da14565de8..d85688e521 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.IO; @@ -6,7 +6,7 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 95ebe7e7a6..ec1b6a8006 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; @@ -8,7 +8,7 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 0d9d9e9638..5f739c7d91 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.IO; @@ -6,7 +6,7 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index a388436b1c..9de25a8e0c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.IO; @@ -8,7 +8,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs index 5b8ed56e53..737d9e1f94 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Testing.xunit; namespace Microsoft.Net.Http.Server { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs index c8bad49ad6..d9240c02bc 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; @@ -8,7 +8,7 @@ namespace Microsoft.Net.Http.Server { // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in - // Microsoft.AspNet.Server.WebListener. + // Microsoft.AspNetCore.Server.WebListener. private const int BasePort = 8001; private const int MaxPort = 11000; private static int NextPort = BasePort; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index 083d02601f..6271d2ae93 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Net.Http; @@ -6,7 +6,7 @@ using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNet.Testing.xunit; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 017ab2aa10..8407d48b4d 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -6,7 +6,7 @@ "dependencies": { "Microsoft.Net.Http.Server": "1.0.0-*", "Microsoft.Net.WebSockets.Server": "1.0.0-*", - "Microsoft.AspNet.Testing": "1.0.0-*", + "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "frameworks": { From 1aff2e9cda1a948a9bf1841cb8399bec42d09c7a Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 22 Jan 2016 12:28:27 -0800 Subject: [PATCH 299/597] Update ASP.NET 5 versions for ASP.NET Core. See https://github.com/aspnet/Announcements/issues/144 for more information. --- samples/HelloWorld/project.json | 40 +++++++++---------- samples/HotAddSample/project.json | 8 ++-- samples/SelfHostServer/project.json | 12 +++--- .../project.json | 8 ++-- src/Microsoft.Net.Http.Server/project.json | 4 +- .../project.json | 6 +-- .../project.json | 4 +- .../project.json | 6 +-- 8 files changed, 45 insertions(+), 43 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 6ba641c8c9..b2cbb497c0 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,22 +1,22 @@ { - "dependencies": { - "Microsoft.Net.Http.Server": "1.0.0-*", - "Microsoft.Net.WebSockets.Server": "1.0.0-*" - }, - "commands": { - "sample": "HelloWorld" - }, - "frameworks": { - "dnx451": { }, - "dnxcore50": { - "dependencies": { - "System.Collections": "4.0.11-*", - "System.Console": "4.0.0-*", - "System.Globalization": "4.0.11-*", - "System.IO": "4.1.0-*", - "System.Runtime": "4.0.21-*", - "System.Threading.Tasks": "4.0.11-*" - } - } + "dependencies": { + "Microsoft.Net.Http.Server": "0.1.0-*", + "Microsoft.Net.WebSockets.Server": "0.1.0-*" + }, + "commands": { + "sample": "HelloWorld" + }, + "frameworks": { + "dnx451": {}, + "dnxcore50": { + "dependencies": { + "System.Collections": "4.0.11-*", + "System.Console": "4.0.0-*", + "System.Globalization": "4.0.11-*", + "System.IO": "4.1.0-*", + "System.Runtime": "4.0.21-*", + "System.Threading.Tasks": "4.0.11-*" + } } -} + } +} \ No newline at end of file diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 22f851418f..e0e8f7fb91 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,7 +1,7 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-*", + "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "compilationOptions": { @@ -11,7 +11,7 @@ "web": "HotAddSample" }, "frameworks": { - "dnx451": { }, - "dnxcore50": { } + "dnx451": {}, + "dnxcore50": {} } -} +} \ No newline at end of file diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 8fd986fded..d868bc2d1e 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,14 +1,16 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-*", + "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "compilationOptions": { "emitEntryPoint": true }, - "commands": { "web": "SelfHostServer" }, + "commands": { + "web": "SelfHostServer" + }, "frameworks": { - "dnx451": { }, - "dnxcore50": { } + "dnx451": {}, + "dnxcore50": {} } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 44917648c5..5c4d638fcf 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -1,21 +1,21 @@ { - "version": "1.0.0-*", + "version": "0.1.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { "Microsoft.AspNetCore.Hosting": "1.0.0-*", "Microsoft.Net.Http.Headers": "1.0.0-*", - "Microsoft.Net.Http.Server": "1.0.0-*" + "Microsoft.Net.Http.Server": "0.1.0-*" }, "compilationOptions": { "allowUnsafe": true, "keyFile": "../../tools/Key.snk" }, "frameworks": { - "net451": { }, + "net451": {}, "dotnet5.4": { "dependencies": { "System.Security.Claims": "4.0.1-*" } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index f314ae21aa..da2b43a592 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "0.1.0-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", @@ -29,4 +29,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 50925126d7..73d00dc129 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -1,8 +1,8 @@ { - "version": "1.0.0-*", + "version": "0.1.0-*", "description": "Implementation of WebSocket abstract base class. Used by WebListener.", "dependencies": { - "Microsoft.Net.Http.Server": "1.0.0-*" + "Microsoft.Net.Http.Server": "0.1.0-*" }, "compilationOptions": { "allowUnsafe": true, @@ -25,4 +25,4 @@ } } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 68da4685aa..112047e7aa 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -4,7 +4,7 @@ "test": "xunit.runner.aspnet" }, "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-*", + "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*" }, "frameworks": { @@ -26,4 +26,4 @@ } } } -} +} \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 8407d48b4d..33a6ef6a0b 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -4,8 +4,8 @@ "test": "xunit.runner.aspnet" }, "dependencies": { - "Microsoft.Net.Http.Server": "1.0.0-*", - "Microsoft.Net.WebSockets.Server": "1.0.0-*", + "Microsoft.Net.Http.Server": "0.1.0-*", + "Microsoft.Net.WebSockets.Server": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, @@ -30,4 +30,4 @@ } } } -} +} \ No newline at end of file From b4eacceb42bbe182449d29331dd1881292745e75 Mon Sep 17 00:00:00 2001 From: John Luo Date: Fri, 22 Jan 2016 11:10:17 -0800 Subject: [PATCH 300/597] Remove request and response logging which has been added in the Hosting layer --- .../RequestProcessing/HeadersLogStructure.cs | 42 ------------- .../RequestProcessing/Request.cs | 63 ------------------- .../RequestProcessing/Response.cs | 56 ----------------- 3 files changed, 161 deletions(-) delete mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/HeadersLogStructure.cs diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeadersLogStructure.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeadersLogStructure.cs deleted file mode 100644 index 26c182df2a..0000000000 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeadersLogStructure.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -using System.Collections; - -namespace Microsoft.Net.Http.Server -{ - internal class HeadersLogStructure : IEnumerable - { - private readonly HeaderCollection _headers; - - internal HeadersLogStructure(HeaderCollection headers) - { - _headers = headers; - } - - IEnumerator IEnumerable.GetEnumerator() - { - foreach (var header in _headers) - { - foreach (var value in header.Value) - { - yield return header.Key + ": " + value; - } - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 5ffebdfb8b..27904ede12 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -150,11 +150,6 @@ namespace Microsoft.Net.Http.Server GetTlsTokenBindingInfo(); // TODO: Verbose log parameters - - if (_requestContext.Logger.IsEnabled(LogLevel.Debug)) - { - RequestContext.Logger.LogDebug(new ReceiveRequestLogContext(this)); - } } internal SslStatus SslStatus @@ -533,63 +528,5 @@ namespace Microsoft.Net.Http.Server _nativeStream = new RequestStream(RequestContext); } } - - private class ReceiveRequestLogContext : ILogValues - { - private readonly Request _request; - - internal ReceiveRequestLogContext(Request request) - { - _request = request; - } - - public string Method { get { return _request.Method; } } - public string PathBase { get { return _request.PathBase; } } - public string Path { get { return _request.Path; } } - public string Query { get { return _request.QueryString; } } - public string Protocol { get { return "HTTP/" + _request.ProtocolVersion.ToString(2); } } - public IEnumerable Headers { get { return new HeadersLogStructure(_request.Headers); } } - - public IEnumerable> GetValues() - { - return new[] - { - new KeyValuePair("Method", Method), - new KeyValuePair("PathBase", PathBase), - new KeyValuePair("Path", Path), - new KeyValuePair("Query", Query), - new KeyValuePair("Protocol", Protocol), - new KeyValuePair("Headers", Headers), - }; - } - - public override string ToString() - { - var requestBuilder = new StringBuilder("Received request: "); - - // GET /path?query HTTP/1.1 - requestBuilder.Append(Method); - requestBuilder.Append(" "); - requestBuilder.Append(PathBase); - requestBuilder.Append(Path); - requestBuilder.Append(Query); - requestBuilder.Append(" "); - requestBuilder.Append(Protocol); - requestBuilder.Append("; Headers: { "); - - foreach (var header in _request.Headers) - { - foreach (var value in header.Value) - { - requestBuilder.Append(header.Key); - requestBuilder.Append(": "); - requestBuilder.Append(value); - requestBuilder.Append("; "); - } - } - requestBuilder.Append("}"); - return requestBuilder.ToString(); - } - } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 668ba5ae42..c7780b6b90 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -356,11 +356,6 @@ namespace Microsoft.Net.Http.Server _responseState = ResponseState.StartedSending; var reasonPhrase = GetReasonPhrase(StatusCode); - if (RequestContext.Logger.IsEnabled(LogLevel.Debug)) - { - RequestContext.Logger.LogDebug(new SendResponseLogContext(this)); - } - /* if (m_BoundaryType==BoundaryType.Raw) { use HTTP_SEND_RESPONSE_FLAG_RAW_HEADER; @@ -823,56 +818,5 @@ namespace Microsoft.Net.Http.Server } } } - - private class SendResponseLogContext : ILogValues - { - private readonly Response _response; - - internal SendResponseLogContext(Response response) - { - _response = response; - } - - public string Protocol { get { return "HTTP/1.1"; } } // HTTP.SYS only allows 1.1 responses. - public string StatusCode { get { return _response.StatusCode.ToString(CultureInfo.InvariantCulture); } } - public string ReasonPhrase { get { return _response.ReasonPhrase ?? _response.GetReasonPhrase(_response.StatusCode); } } - public IEnumerable Headers { get { return new HeadersLogStructure(_response.Headers); } } - - public IEnumerable> GetValues() - { - return new[] - { - new KeyValuePair("Protocol", Protocol), - new KeyValuePair("StatusCode", StatusCode), - new KeyValuePair("ReasonPhrase", ReasonPhrase), - new KeyValuePair("Headers", Headers), - }; - } - - public override string ToString() - { - // HTTP/1.1 200 OK - var responseBuilder = new StringBuilder("Sending Response: "); - responseBuilder.Append(Protocol); - responseBuilder.Append(" "); - responseBuilder.Append(StatusCode); - responseBuilder.Append(" "); - responseBuilder.Append(ReasonPhrase); - responseBuilder.Append("; Headers: { "); - - foreach (var header in _response.Headers) - { - foreach (var value in header.Value) - { - responseBuilder.Append(header.Key); - responseBuilder.Append(": "); - responseBuilder.Append(value); - responseBuilder.Append("; "); - } - } - responseBuilder.Append("}"); - return responseBuilder.ToString(); - } - } } } From 247c46da1cec028c508efce4c223697e72dac8bc Mon Sep 17 00:00:00 2001 From: Brennan Date: Thu, 21 Jan 2016 10:09:28 -0800 Subject: [PATCH 301/597] React to Logging API changes --- src/Microsoft.Net.Http.Server/LogHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index 98b009afa2..7ac8e13957 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -99,7 +99,7 @@ namespace Microsoft.Net.Http.Server return false; } - public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func formatter) + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { } From dfac28da89263d58dace5f98e8bc6159da352171 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 1 Feb 2016 12:33:38 -0800 Subject: [PATCH 302/597] Fix warnings, enable warningsAsErrors --- samples/TestClient/Program.cs | 4 ++-- src/Microsoft.AspNetCore.Server.WebListener/project.json | 1 + .../Overlapped/PreAllocatedOverlapped.cs | 1 - .../Overlapped/ThreadPoolBoundHandle.cs | 8 ++++---- src/Microsoft.Net.Http.Server/project.json | 1 + src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs | 2 +- src/Microsoft.Net.WebSockets.Server/project.json | 1 + 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/samples/TestClient/Program.cs b/samples/TestClient/Program.cs index 23c53b8f89..f57945de42 100644 --- a/samples/TestClient/Program.cs +++ b/samples/TestClient/Program.cs @@ -45,8 +45,8 @@ namespace TestClient } // RunWebSocketClient().Wait(); - Console.WriteLine("Done"); - Console.ReadKey(); + // Console.WriteLine("Done"); + // Console.ReadKey(); } public static async Task RunWebSocketClient() diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 5c4d638fcf..2708965453 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -8,6 +8,7 @@ }, "compilationOptions": { "allowUnsafe": true, + "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" }, "frameworks": { diff --git a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs index 465c816391..92572dc9f4 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs @@ -6,7 +6,6 @@ namespace System.Threading { internal readonly ThreadPoolBoundHandleOverlapped _overlapped; private DeferredDisposableLifetime _lifetime; - [CLSCompliant(false)] public PreAllocatedOverlapped(IOCompletionCallback callback, object state, object pinData) { if (callback == null) diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs index 3b7ad7d966..595d347a57 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs @@ -46,7 +46,7 @@ namespace System.Threading } return new ThreadPoolBoundHandle(handle); } - [CLSCompliant(false)] + public unsafe NativeOverlapped* AllocateNativeOverlapped(IOCompletionCallback callback, object state, object pinData) { if (callback == null) @@ -59,7 +59,7 @@ namespace System.Threading _boundHandle = this }._nativeOverlapped; } - [CLSCompliant(false)] + public unsafe NativeOverlapped* AllocateNativeOverlapped(PreAllocatedOverlapped preAllocated) { if (preAllocated == null) @@ -86,7 +86,7 @@ namespace System.Threading } return nativeOverlapped; } - [CLSCompliant(false)] + public unsafe void FreeNativeOverlapped(NativeOverlapped* overlapped) { if (overlapped == null) @@ -105,7 +105,7 @@ namespace System.Threading } Overlapped.Free(overlapped); } - [CLSCompliant(false)] + public unsafe static object GetNativeOverlappedState(NativeOverlapped* overlapped) { if (overlapped == null) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index da2b43a592..c63d55703f 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -7,6 +7,7 @@ }, "compilationOptions": { "allowUnsafe": true, + "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" }, "frameworks": { diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs index e71d463f7f..1c87e73334 100644 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs +++ b/src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs @@ -66,7 +66,7 @@ namespace Microsoft.Net.WebSockets private readonly ArraySegment _PropertyBuffer; private readonly int _SendBufferSize; private volatile int _PayloadOffset; - private volatile WebSocketReceiveResult _BufferedPayloadReceiveResult; + private WebSocketReceiveResult _BufferedPayloadReceiveResult; private long _PinnedSendBufferStartAddress; private long _PinnedSendBufferEndAddress; private ArraySegment _PinnedSendBuffer; diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 73d00dc129..cc2fce2d21 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -6,6 +6,7 @@ }, "compilationOptions": { "allowUnsafe": true, + "warningsAsErrors": true, "keyFile": "../../tools/Key.snk" }, "frameworks": { From 4666564b87b392015fbd4221c1a6acd6e69350f0 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 1 Feb 2016 19:21:41 -0800 Subject: [PATCH 303/597] Updating to new CLI --- samples/HelloWorld/project.json | 3 ++- samples/HotAddSample/project.json | 3 ++- samples/SelfHostServer/project.json | 3 ++- src/Microsoft.AspNetCore.Server.WebListener/project.json | 3 ++- .../project.json | 6 ++++-- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 4 +++- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index b2cbb497c0..9f94bb7a69 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,7 +1,8 @@ { "dependencies": { "Microsoft.Net.Http.Server": "0.1.0-*", - "Microsoft.Net.WebSockets.Server": "0.1.0-*" + "Microsoft.Net.WebSockets.Server": "0.1.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "commands": { "sample": "HelloWorld" diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index e0e8f7fb91..9eb1fe1013 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -2,7 +2,8 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "compilationOptions": { "emitEntryPoint": true diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index d868bc2d1e..ded562b37c 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,8 @@ { "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "compilationOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 2708965453..4fedde9e11 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -16,7 +16,8 @@ "dotnet5.4": { "dependencies": { "System.Security.Claims": "4.0.1-*" - } + }, + "imports": "portable-net451+win8" } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 112047e7aa..103d616411 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -5,7 +5,8 @@ }, "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.AspNetCore.Testing": "1.0.0-*" + "Microsoft.AspNetCore.Testing": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "frameworks": { "dnx451": { @@ -23,7 +24,8 @@ "System.Net.Requests": "4.0.11-*", "System.Net.WebHeaderCollection": "4.0.1-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" - } + }, + "imports": "portable-net451+win8" } } } \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 33a6ef6a0b..5fcc744ab5 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -7,6 +7,7 @@ "Microsoft.Net.Http.Server": "0.1.0-*", "Microsoft.Net.WebSockets.Server": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "frameworks": { @@ -27,7 +28,8 @@ "System.Net.Requests": "4.0.11-*", "System.Net.WebSockets.Client": "4.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" - } + }, + "imports": "portable-net451+win8" } } } \ No newline at end of file From d2ea17c6f0ac6a2ceff8d672dd954208ccc04244 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 5 Feb 2016 17:22:28 -0800 Subject: [PATCH 304/597] Update project.json to remove redundant System.Runtime dependency. - This package is pulled in transitively. --- samples/HelloWorld/project.json | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 9f94bb7a69..2bdad3b44c 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -15,7 +15,6 @@ "System.Console": "4.0.0-*", "System.Globalization": "4.0.11-*", "System.IO": "4.1.0-*", - "System.Runtime": "4.0.21-*", "System.Threading.Tasks": "4.0.11-*" } } From fe9aa69970b11fbe688bf5172ec21b79569941df Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 8 Feb 2016 09:33:50 -0800 Subject: [PATCH 305/597] Reacting to CoreCLR package version changes --- src/Microsoft.Net.Http.Server/project.json | 2 +- src/Microsoft.Net.WebSockets.Server/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index c63d55703f..66c1776780 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -21,7 +21,7 @@ "System.IO": "4.1.0-*", "System.IO.FileSystem": "4.0.1-*", "System.Net.Primitives": "4.0.11-*", - "System.Runtime.InteropServices": "4.0.21-*", + "System.Runtime.InteropServices": "4.1.0-*", "System.Security.Claims": "4.0.1-*", "System.Security.Cryptography.X509Certificates": "4.0.0-*", "System.Security.Principal.Windows": "4.0.0-*", diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index cc2fce2d21..175eaaa822 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -14,7 +14,7 @@ "dotnet5.4": { "dependencies": { "System.Collections": "4.0.11-*", - "System.Linq": "4.0.1-*", + "System.Linq": "4.0.2-*", "System.Net.WebSockets": "4.0.0-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", From c79458a2825096d90d630c0266708dbe7cc5a0b4 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 10 Feb 2016 13:38:06 -0800 Subject: [PATCH 306/597] React to changes in System.Net.Sockets.TcpClient. --- .../ServerTests.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs index 37660b5380..2c95f450bb 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs @@ -204,16 +204,14 @@ namespace Microsoft.AspNetCore.Server.WebListener { // Note: System.Net.Sockets does not RST the connection by default, it just FINs. // Http.Sys's disconnect notice requires a RST. - using (Socket socket = await SendHungRequestAsync("GET", address)) + using (var client = await SendHungRequestAsync("GET", address)) { Assert.True(received.WaitOne(interval), "Receive Timeout"); // Force a RST - socket.LingerState = new LingerOption(true, 0); - socket.Dispose(); - - aborted.Set(); + client.LingerState = new LingerOption(true, 0); } + aborted.Set(); Assert.True(canceled.WaitOne(interval), "canceled"); } } @@ -240,10 +238,10 @@ namespace Microsoft.AspNetCore.Server.WebListener return Task.FromResult(0); })) { - using (Socket socket = await SendHungRequestAsync("GET", address)) + using (var client = await SendHungRequestAsync("GET", address)) { Assert.True(received.WaitOne(interval), "Receive Timeout"); - Assert.Throws(() => socket.Receive(new byte[10])); + Assert.Throws(() => client.GetStream().Read(new byte[10], 0, 10)); } } } @@ -287,7 +285,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - private async Task SendHungRequestAsync(string method, string address) + private async Task SendHungRequestAsync(string method, string address) { // Connect with a socket Uri uri = new Uri(address); @@ -302,8 +300,7 @@ namespace Microsoft.AspNetCore.Server.WebListener byte[] requestBytes = BuildGetRequest(method, uri); await stream.WriteAsync(requestBytes, 0, requestBytes.Length); - // Return the opaque network stream - return client.Client; + return client; } catch (Exception) { From 8007020bffaddff9059282342dcaf823add03a25 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Wed, 10 Feb 2016 15:09:37 -0800 Subject: [PATCH 307/597] Fix build. --- .../project.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 103d616411..43df05c50c 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -12,7 +12,8 @@ "dnx451": { "frameworkAssemblies": { "System.Net.Http": "", - "System.Net.Http.WebRequest": "" + "System.Net.Http.WebRequest": "", + "System.Threading.Tasks": "" }, "dependencies": { "xunit.runner.console": "2.1.0" From 5061848e9eda66255b254d671dd25d4991971888 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 11 Feb 2016 14:22:53 -0800 Subject: [PATCH 308/597] Add IHttpConnectionFeature.ConnectionId. --- .../FeatureContext.cs | 15 +++++++++++++++ .../RequestProcessing/Request.cs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index 4068da2818..dd0408237b 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -16,6 +16,7 @@ // permissions and limitations under the License. using System; +using System.Globalization; using System.IO; using System.Net; using System.Net.WebSockets; @@ -65,6 +66,7 @@ namespace Microsoft.AspNetCore.Server.WebListener private IPAddress _localIpAddress; private int? _remotePort; private int? _localPort; + private string _connectionId; private string _requestId; private X509Certificate2 _clientCert; private ClaimsPrincipal _user; @@ -270,6 +272,19 @@ namespace Microsoft.AspNetCore.Server.WebListener set { _remotePort = value; } } + string IHttpConnectionFeature.ConnectionId + { + get + { + if (_connectionId == null) + { + _connectionId = Request.ConnectionId.ToString(CultureInfo.InvariantCulture); + } + return _connectionId; + } + set { _connectionId = value; } + } + X509Certificate2 ITlsConnectionFeature.ClientCertificate { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 27904ede12..953556d88a 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -160,7 +160,7 @@ namespace Microsoft.Net.Http.Server } } - internal ulong ConnectionId + public ulong ConnectionId { get { From 9b0afe0d1be7267928e9cbfa006b974e91cfbc5c Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 18 Feb 2016 15:36:09 -0800 Subject: [PATCH 309/597] Update System.Linq 4.0.2-* => 4.1.0-*. --- src/Microsoft.Net.WebSockets.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 175eaaa822..4950a5428b 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -14,7 +14,7 @@ "dotnet5.4": { "dependencies": { "System.Collections": "4.0.11-*", - "System.Linq": "4.0.2-*", + "System.Linq": "4.1.0-*", "System.Net.WebSockets": "4.0.0-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", From 497565a52c8e48c3a6ab934fa8ce0f7bbd184286 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 18 Feb 2016 16:00:58 -0800 Subject: [PATCH 310/597] Updating test TFMs for custom test discovery --- .../HttpsTests.cs | 4 +-- .../ResponseBodyTests.cs | 2 +- .../project.json | 28 ++++++++--------- .../HttpsTests.cs | 4 +-- .../RequestBodyTests.cs | 2 +- .../ResponseBodyTests.cs | 2 +- .../SkipOffDomainAttribute.cs | 2 +- .../project.json | 31 +++++++++---------- 8 files changed, 36 insertions(+), 39 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs index 7616dc5392..bffcf16ceb 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Server.WebListener private async Task SendRequestAsync(string uri, X509Certificate cert = null) { -#if DNX451 +#if NET451 var handler = new WebRequestHandler(); #else var handler = new WinHttpHandler(); @@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.WebListener private async Task SendRequestAsync(string uri, string upload) { -#if DNX451 +#if NET451 var handler = new WebRequestHandler(); #else var handler = new WinHttpHandler(); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 42224e5df3..b87a5fbfcb 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -103,7 +103,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { httpContext.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = httpContext.Response.Body; -#if DNX451 +#if NET451 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); #else await stream.WriteAsync(new byte[10], 0, 10); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 43df05c50c..001a9e016a 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -1,15 +1,22 @@ { "testRunner": "xunit", - "commands": { - "test": "xunit.runner.aspnet" - }, "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.NETCore.Platforms": "1.0.1-*", + "xunit": "2.1.0" }, "frameworks": { - "dnx451": { + "dnxcore50": { + "dependencies": { + "System.Net.Http.WinHttpHandler": "4.0.0-*", + "System.Net.Requests": "4.0.11-*", + "System.Net.WebHeaderCollection": "4.0.1-*", + "dotnet-test-xunit": "1.0.0-dev-*" + }, + "imports": "portable-net451+win8" + }, + "net451": { "frameworkAssemblies": { "System.Net.Http": "", "System.Net.Http.WebRequest": "", @@ -18,15 +25,6 @@ "dependencies": { "xunit.runner.console": "2.1.0" } - }, - "dnxcore50": { - "dependencies": { - "System.Net.Http.WinHttpHandler": "4.0.0-*", - "System.Net.Requests": "4.0.11-*", - "System.Net.WebHeaderCollection": "4.0.1-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "imports": "portable-net451+win8" } } -} \ No newline at end of file +} diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index 05931b0ad1..73f915d3b8 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -107,7 +107,7 @@ namespace Microsoft.Net.Http.Server private async Task SendRequestAsync(string uri, X509Certificate cert = null) { -#if DNX451 +#if NET451 WebRequestHandler handler = new WebRequestHandler(); #else WinHttpHandler handler = new WinHttpHandler(); @@ -125,7 +125,7 @@ namespace Microsoft.Net.Http.Server private async Task SendRequestAsync(string uri, string upload) { -#if DNX451 +#if NET451 WebRequestHandler handler = new WebRequestHandler(); #else WinHttpHandler handler = new WinHttpHandler(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index b9423dac99..d647cd70d9 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -51,7 +51,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal("Hello World", response); } } -#if DNX451 +#if NET451 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index ec1b6a8006..39dc2adcbc 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -122,7 +122,7 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = context.Response.Body; -#if DNX451 +#if NET451 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); #else await stream.WriteAsync(new byte[10], 0, 10); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs index 737d9e1f94..bbe6c7fdbc 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs @@ -18,7 +18,7 @@ namespace Microsoft.Net.Http.Server { try { -#if DNX451 +#if NET451 return !string.IsNullOrEmpty(System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name); #endif } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 5fcc744ab5..1abe854726 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,35 +1,34 @@ { "testRunner": "xunit", - "commands": { - "test": "xunit.runner.aspnet" - }, "dependencies": { "Microsoft.Net.Http.Server": "0.1.0-*", "Microsoft.Net.WebSockets.Server": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "xunit": "2.1.0" }, "frameworks": { - "dnx451": { - "frameworkAssemblies": { - "System.DirectoryServices": "", - "System.Net.Http": "", - "System.Net.Http.WebRequest": "" - }, - "dependencies": { - "xunit.runner.console": "2.1.0" - } - }, "dnxcore50": { "dependencies": { "System.Net.Http": "4.0.1-*", "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebSockets.Client": "4.0.0-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" + "dotnet-test-xunit": "1.0.0-dev-*" }, "imports": "portable-net451+win8" + }, + "net451": { + "frameworkAssemblies": { + "System.DirectoryServices": "", + "System.Net.Http": "", + "System.Net.Http.WebRequest": "", + "System.Runtime": "", + "System.Threading.Tasks": "" + }, + "dependencies": { + "xunit.runner.console": "2.1.0" + } } } -} \ No newline at end of file +} From b5ff692dbfde2c477afd970b7871313536510f17 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Fri, 19 Feb 2016 12:25:51 -0800 Subject: [PATCH 311/597] Enabled xml doc generation --- NuGetPackageVerifier.json | 14 ++------------ .../project.json | 4 +++- src/Microsoft.Net.Http.Server/Helpers.cs | 1 - .../NativeInterop/AddressFamily.cs | 10 +++++++++- src/Microsoft.Net.Http.Server/UrlPrefix.cs | 2 +- src/Microsoft.Net.Http.Server/project.json | 4 +++- src/Microsoft.Net.WebSockets.Server/project.json | 4 +++- 7 files changed, 21 insertions(+), 18 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index e087c17fa1..d13c12ca63 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,12 +1,7 @@ { "adx": { // Packages written by the ADX team and that ship on NuGet.org "rules": [ - "AssemblyHasDocumentFileRule", - "AssemblyHasVersionAttributesRule", - "AssemblyHasServicingAttributeRule", - "AssemblyHasNeutralResourcesLanguageAttributeRule", - "SatellitePackageRule", - "StrictSemanticVersionValidationRule" + "AdxVerificationCompositeRule" ], "packages": { "Microsoft.AspNetCore.Server.WebListener": { }, @@ -16,12 +11,7 @@ }, "Default": { // Ru les to run for packages not listed in any other set. "rules": [ - "AssemblyHasDocumentFileRule", - "AssemblyHasVersionAttributesRule", - "AssemblyHasServicingAttributeRule", - "AssemblyHasNeutralResourcesLanguageAttributeRule", - "SatellitePackageRule", - "StrictSemanticVersionValidationRule" + "DefaultCompositeRule" ] } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 4fedde9e11..3c73aa60b2 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -9,7 +9,9 @@ "compilationOptions": { "allowUnsafe": true, "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.Net.Http.Server/Helpers.cs b/src/Microsoft.Net.Http.Server/Helpers.cs index 428edffa1d..a117fe2490 100644 --- a/src/Microsoft.Net.Http.Server/Helpers.cs +++ b/src/Microsoft.Net.Http.Server/Helpers.cs @@ -88,7 +88,6 @@ namespace Microsoft.Net.Http.Server /// Generates a right-aligned hex string and returns the start offset. /// /// Chunk size to be encoded - /// Out parameter where we store offset into buffer. /// A byte array with the header in int. internal static ArraySegment GetChunkHeader(int size) { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs b/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs index c1c6def0cf..cc7f44b913 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs @@ -23,12 +23,20 @@ namespace Microsoft.Net.Http.Server { +#if NET451 /// /// - /// Specifies the address families that an instance of the + /// Specifies the address families that an instance of the /// class can use. /// /// +#else + /// + /// + /// Specifies the address families. + /// + /// +#endif internal enum AddressFamily { /// diff --git a/src/Microsoft.Net.Http.Server/UrlPrefix.cs b/src/Microsoft.Net.Http.Server/UrlPrefix.cs index 34689b9eac..8e72903252 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefix.cs @@ -62,7 +62,7 @@ namespace Microsoft.Net.Http.Server /// /// http or https. Will be normalized to lower case. /// +, *, IPv4, [IPv6], or a dns name. Http.Sys does not permit punycode (xn--), use Unicode instead. - /// If empty, the default port for the given scheme will be used (80 or 443). + /// If empty, the default port for the given scheme will be used (80 or 443). /// Should start and end with a '/', though a missing trailing slash will be added. This value must be un-escaped. public static UrlPrefix Create(string scheme, string host, int? portValue, string path) { diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 66c1776780..5b5861dd58 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -8,7 +8,9 @@ "compilationOptions": { "allowUnsafe": true, "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 4950a5428b..7d83e64239 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -7,7 +7,9 @@ "compilationOptions": { "allowUnsafe": true, "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true }, "frameworks": { "net451": {}, From c035f3b02992b5010ad59b03732f825c88af6b58 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 24 Feb 2016 13:12:43 -0800 Subject: [PATCH 312/597] Update `build.cmd` to match latest template - aspnet/Universe#347 - `%KOREBUILD_VERSION%` doesn't work without this fix --- build.cmd | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.cmd b/build.cmd index ebb619e737..95b049cf63 100644 --- a/build.cmd +++ b/build.cmd @@ -2,7 +2,7 @@ SETLOCAL SET REPO_FOLDER=%~dp0 -CD %REPO_FOLDER% +CD "%REPO_FOLDER%" SET BUILD_FOLDER=.build SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet @@ -28,12 +28,11 @@ IF NOT EXIST %NUGET_PATH% ( copy %CACHED_NUGET% %NUGET_PATH% > nul ) +SET KOREBUILD_DOWNLOAD_ARGS= +IF NOT "%KOREBUILD_VERSION%"=="" ( + SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% +) IF NOT EXIST %KOREBUILD_FOLDER% ( - SET KOREBUILD_DOWNLOAD_ARGS= - IF NOT "%KOREBUILD_VERSION%"=="" ( - SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% - ) - %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% ) From 5e8295afcba8998bb4f633cf0d51f3b594526d9b Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Sat, 27 Feb 2016 12:51:11 -0800 Subject: [PATCH 313/597] Update the build scripts --- build.cmd | 41 ++----------------------------------- build.ps1 | 36 +++++++++++++++++++++++++++++++++ build.sh | 60 +++++++++++++++++++++++-------------------------------- 3 files changed, 63 insertions(+), 74 deletions(-) create mode 100644 build.ps1 diff --git a/build.cmd b/build.cmd index 95b049cf63..2fa024b15e 100644 --- a/build.cmd +++ b/build.cmd @@ -1,39 +1,2 @@ -@ECHO off -SETLOCAL - -SET REPO_FOLDER=%~dp0 -CD "%REPO_FOLDER%" - -SET BUILD_FOLDER=.build -SET KOREBUILD_FOLDER=%BUILD_FOLDER%\KoreBuild-dotnet -SET KOREBUILD_VERSION= - -SET NUGET_PATH=%BUILD_FOLDER%\NuGet.exe -SET NUGET_VERSION=latest -SET CACHED_NUGET=%LocalAppData%\NuGet\nuget.%NUGET_VERSION%.exe - -IF NOT EXIST %BUILD_FOLDER% ( - md %BUILD_FOLDER% -) - -IF NOT EXIST %NUGET_PATH% ( - IF NOT EXIST %CACHED_NUGET% ( - echo Downloading latest version of NuGet.exe... - IF NOT EXIST %LocalAppData%\NuGet ( - md %LocalAppData%\NuGet - ) - @powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/%NUGET_VERSION%/nuget.exe' -OutFile '%CACHED_NUGET%'" - ) - - copy %CACHED_NUGET% %NUGET_PATH% > nul -) - -SET KOREBUILD_DOWNLOAD_ARGS= -IF NOT "%KOREBUILD_VERSION%"=="" ( - SET KOREBUILD_DOWNLOAD_ARGS=-version %KOREBUILD_VERSION% -) -IF NOT EXIST %KOREBUILD_FOLDER% ( - %BUILD_FOLDER%\nuget.exe install KoreBuild-dotnet -ExcludeVersion -o %BUILD_FOLDER% -nocache -pre %KOREBUILD_DOWNLOAD_ARGS% -) - -"%KOREBUILD_FOLDER%\build\KoreBuild.cmd" %* +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*" \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..4fd24a30d5 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,36 @@ +cd $PSScriptRoot + +$repoFolder = $PSScriptRoot +$env:REPO_FOLDER = $repoFolder + +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +if ($env:KOREBUILD_ZIP) +{ + $koreBuildZip=$env:KOREBUILD_ZIP +} + +$buildFolder = ".build" +$buildFile="$buildFolder\KoreBuild.ps1" + +if (!(Test-Path $buildFolder)) { + Write-Host "Downloading KoreBuild from $koreBuildZip" + + $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() + New-Item -Path "$tempFolder" -Type directory | Out-Null + + $localZipFile="$tempFolder\korebuild.zip" + + Invoke-WebRequest $koreBuildZip -OutFile $localZipFile + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) + + New-Item -Path "$buildFolder" -Type directory | Out-Null + copy-item "$tempFolder\**\build\*" $buildFolder -Recurse + + # Cleanup + if (Test-Path $tempFolder) { + Remove-Item -Recurse -Force $tempFolder + } +} + +&"$buildFile" $args \ No newline at end of file diff --git a/build.sh b/build.sh index 263fb667a8..79638d06b6 100755 --- a/build.sh +++ b/build.sh @@ -1,45 +1,35 @@ #!/usr/bin/env bash +repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $repoFolder -buildFolder=.build -koreBuildFolder=$buildFolder/KoreBuild-dotnet - -nugetPath=$buildFolder/nuget.exe - -if test `uname` = Darwin; then - cachedir=~/Library/Caches/KBuild -else - if [ -z $XDG_DATA_HOME ]; then - cachedir=$HOME/.local/share - else - cachedir=$XDG_DATA_HOME; - fi +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +if [ ! -z $KOREBUILD_ZIP ]; then + koreBuildZip=$KOREBUILD_ZIP fi -mkdir -p $cachedir -nugetVersion=latest -cacheNuget=$cachedir/nuget.$nugetVersion.exe -nugetUrl=https://dist.nuget.org/win-x86-commandline/$nugetVersion/nuget.exe +buildFolder=".build" +buildFile="$buildFolder/KoreBuild.sh" if test ! -d $buildFolder; then + echo "Downloading KoreBuild from $koreBuildZip" + + tempFolder="/tmp/KoreBuild-$(uuidgen)" + mkdir $tempFolder + + localZipFile="$tempFolder/korebuild.zip" + + wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip /dev/null + unzip -q -d $tempFolder $localZipFile + mkdir $buildFolder -fi - -if test ! -f $nugetPath; then - if test ! -f $cacheNuget; then - wget -O $cacheNuget $nugetUrl 2>/dev/null || curl -o $cacheNuget --location $nugetUrl /dev/null + cp -r $tempFolder/**/build/** $buildFolder + + chmod +x $buildFile + + # Cleanup + if test ! -d $tempFolder; then + rm -rf $tempFolder fi - - cp $cacheNuget $nugetPath fi -if test ! -d $koreBuildFolder; then - mono $nugetPath install KoreBuild-dotnet -ExcludeVersion -o $buildFolder -nocache -pre - chmod +x $koreBuildFolder/build/KoreBuild.sh -fi - -makeFile=makefile.shade -if [ ! -e $makeFile ]; then - makeFile=$koreBuildFolder/build/makefile.shade -fi - -./$koreBuildFolder/build/KoreBuild.sh -n $nugetPath -m $makeFile "$@" +$buildFile -r $repoFolder "$@" From eafda23e80f413adf7925c74a7908754b8ca5962 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Sun, 28 Feb 2016 10:12:15 -0800 Subject: [PATCH 314/597] Return the error code from build.cmd --- build.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cmd b/build.cmd index 2fa024b15e..7d4894cb4a 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file From 54331301827af00d18567a507e21efe2091a85da Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 1 Mar 2016 13:35:50 -0800 Subject: [PATCH 315/597] Transition to netstandard. - dotnet5.X => netstandard1.y (where y = x-1). - DNXCore50 => netstandardapp1.5. - Applied the same changes to ifdefs. --- samples/HelloWorld/project.json | 7 +++-- samples/HotAddSample/project.json | 6 +++- samples/SelfHostServer/project.json | 6 +++- .../project.json | 11 ++++++-- .../NativeInterop/ComNetOS.cs | 2 +- .../NativeInterop/HttpSysSettings.cs | 6 ++-- .../NativeInterop/NclUtilities.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 28 +++++++++---------- .../Overlapped/DeferredDisposableLifetime.cs | 2 +- .../Overlapped/IDeferredDisposable.cs | 2 +- .../Overlapped/PreAllocatedOverlapped.cs | 2 +- .../Overlapped/ThreadPoolBoundHandle.cs | 2 +- .../ThreadPoolBoundHandleOverlapped.cs | 2 +- .../RequestProcessing/OpaqueStream.cs | 4 +-- .../RequestProcessing/RequestStream.cs | 8 +++--- .../RequestProcessing/ResponseStream.cs | 6 ++-- .../ResponseStreamAsyncResult.cs | 2 +- .../WebListenerException.cs | 2 +- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 2 +- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 2 +- .../fx/System/Diagnostics/TraceEventType.cs | 2 +- .../fx/System/ExternDll.cs | 2 +- .../InteropServices/ExternalException.cs | 2 +- .../fx/System/SafeNativeMethods.cs | 2 +- src/Microsoft.Net.Http.Server/project.json | 11 ++++++-- .../NativeInterop/UnsafeNativeMethods.cs | 8 +++--- .../WebSocketBase.cs | 6 ++-- .../WebSocketException.cs | 4 +-- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 2 +- .../fx/System/AccessViolationException.cs | 2 +- .../fx/System/ExternDll.cs | 2 +- .../InteropServices/ExternalException.cs | 2 +- .../fx/System/SafeNativeMethods.cs | 2 +- .../fx/System/SystemException.cs | 2 +- .../project.json | 11 ++++++-- .../RequestBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 4 +-- .../project.json | 9 ++++-- .../ResponseBodyTests.cs | 6 ++-- .../ResponseHeaderTests.cs | 6 ++-- .../ServerTests.cs | 2 +- .../project.json | 9 ++++-- 42 files changed, 117 insertions(+), 85 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 2bdad3b44c..2d80d1f40d 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -9,14 +9,17 @@ }, "frameworks": { "dnx451": {}, - "dnxcore50": { + "netstandardapp1.5": { "dependencies": { "System.Collections": "4.0.11-*", "System.Console": "4.0.0-*", "System.Globalization": "4.0.11-*", "System.IO": "4.1.0-*", "System.Threading.Tasks": "4.0.11-*" - } + }, + "imports": [ + "dnxcore50" + ] } } } \ No newline at end of file diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 9eb1fe1013..dde0f7325a 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -13,6 +13,10 @@ }, "frameworks": { "dnx451": {}, - "dnxcore50": {} + "netstandardapp1.5": { + "imports": [ + "dnxcore50" + ] + } } } \ No newline at end of file diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index ded562b37c..e31b464c7b 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -12,6 +12,10 @@ }, "frameworks": { "dnx451": {}, - "dnxcore50": {} + "netstandardapp1.5": { + "imports": [ + "dnxcore50" + ] + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 3c73aa60b2..b2a504e17f 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -10,16 +10,21 @@ "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", - "nowarn": [ "CS1591" ], + "nowarn": [ + "CS1591" + ], "xmlDoc": true }, "frameworks": { "net451": {}, - "dotnet5.4": { + "netstandard1.3": { "dependencies": { "System.Security.Claims": "4.0.1-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dotnet5.4", + "portable-net451+win8" + ] } } } \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index 11333417cb..e48bc24d6b 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server static ComNetOS() { -#if DOTNET5_4 +#if NETSTANDARD1_3 // TODO: SkipIOCPCallbackOnSuccess doesn't work on Win7. Need a way to detect Win7 vs 8+. IsWin8orLater = false; #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs index 46e3aee54d..946345193c 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Security; -#if !DOTNET5_4 +#if !NETSTANDARD1_3 using Microsoft.Win32; #endif @@ -34,7 +34,7 @@ namespace Microsoft.Net.Http.Server { internal static class HttpSysSettings { -#if !DOTNET5_4 +#if !NETSTANDARD1_3 private const string HttpSysParametersKey = @"System\CurrentControlSet\Services\HTTP\Parameters"; #endif private const bool EnableNonUtf8Default = true; @@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server } private static void ReadHttpSysRegistrySettings() -#if DOTNET5_4 +#if NETSTANDARD1_3 { } #else diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs index 8c939d7bc2..7901200e79 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server get { return Environment.HasShutdownStarted -#if !DOTNET5_4 +#if !NETSTANDARD1_3 || AppDomain.CurrentDomain.IsFinalizingForUnload() #endif ; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index e9171f7a8a..8329a27cab 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -33,7 +33,7 @@ namespace Microsoft.Net.Http.Server { private const string HTTPAPI = "httpapi.dll"; -#if DOTNET5_4 +#if NETSTANDARD1_3 private const string sspicli_LIB = "sspicli.dll"; private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-1.dll"; @@ -63,21 +63,21 @@ namespace Microsoft.Net.Http.Server internal const uint ERROR_CONNECTION_INVALID = 1229; } -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_processthreads_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #endif internal static extern uint GetCurrentThreadId(); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_io_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #endif internal static unsafe extern uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_kernel32_legacy_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] @@ -102,7 +102,7 @@ namespace Microsoft.Net.Http.Server [Out] out HeapAllocHandle resultList); // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366569(v=vs.85).aspx -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)] #else [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)] @@ -110,7 +110,7 @@ namespace Microsoft.Net.Http.Server internal static extern IntPtr GetProcessHeap(); // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366701(v=vs.85).aspx -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)] #else [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)] @@ -122,7 +122,7 @@ namespace Microsoft.Net.Http.Server internal static class SafeNetHandles { -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] @@ -130,7 +130,7 @@ namespace Microsoft.Net.Http.Server internal static extern int FreeContextBuffer( [In] IntPtr contextBuffer); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] @@ -147,21 +147,21 @@ namespace Microsoft.Net.Http.Server [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern bool CloseHandle(IntPtr handle); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_obsolete_LIB, EntryPoint = "LocalAlloc", SetLastError = true)] #else [DllImport(KERNEL32, EntryPoint = "LocalAlloc", SetLastError = true)] @@ -169,21 +169,21 @@ namespace Microsoft.Net.Http.Server internal static extern SafeLocalFreeChannelBinding LocalAllocChannelBinding(int uFlags, UIntPtr sizetdwBytes); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern IntPtr LocalFree(IntPtr handle); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #endif internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] diff --git a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs index 80ac921a01..a897da7d0e 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs @@ -1,4 +1,4 @@ -#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. +#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading { diff --git a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs index 57bf6b41f7..b45b7a2c8f 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs @@ -1,4 +1,4 @@ -#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. +#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading { diff --git a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs index 92572dc9f4..7d30b4e248 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs @@ -1,4 +1,4 @@ -#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. +#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading { diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs index 595d347a57..4356a57f7a 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs @@ -1,4 +1,4 @@ -#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. +#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; using System.Runtime.InteropServices; namespace System.Threading diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs index 753ee35ffd..55e5458f04 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs @@ -1,4 +1,4 @@ -#if !DOTNET5_4 // TODO: Temp copy. Remove once we target net46. +#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs index 4889a8c41b..6de4a8b38d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs @@ -109,7 +109,7 @@ namespace Microsoft.Net.Http.Server { return _requestStream.ReadByte(); } -#if !DOTNET5_4 +#if !NETSTANDARD1_3 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _requestStream.BeginRead(buffer, offset, count, callback, state); @@ -143,7 +143,7 @@ namespace Microsoft.Net.Http.Server { _responseStream.WriteByte(value); } -#if !DOTNET5_4 +#if !NETSTANDARD1_3 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _responseStream.BeginWrite(buffer, offset, count, callback, state); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 162c8d683e..059dfe6822 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -203,7 +203,7 @@ namespace Microsoft.Net.Http.Server } } -#if DOTNET5_4 +#if NETSTANDARD1_3 public unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -293,7 +293,7 @@ namespace Microsoft.Net.Http.Server return asyncResult; } -#if DOTNET5_4 +#if NETSTANDARD1_3 public int EndRead(IAsyncResult asyncResult) #else public override int EndRead(IAsyncResult asyncResult) @@ -428,7 +428,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if DOTNET5_4 +#if NETSTANDARD1_3 public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) #else public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) @@ -437,7 +437,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if DOTNET5_4 +#if NETSTANDARD1_3 public void EndWrite(IAsyncResult asyncResult) #else public override void EndWrite(IAsyncResult asyncResult) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 579dd1bbe2..fc0919602b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -379,7 +379,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } -#if !DOTNET5_4 +#if !NETSTANDARD1_3 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); @@ -468,7 +468,7 @@ namespace Microsoft.Net.Http.Server } } -#if DOTNET5_4 +#if NETSTANDARD1_3 public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) #else public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) @@ -476,7 +476,7 @@ namespace Microsoft.Net.Http.Server { return WriteAsync(buffer, offset, count).ToIAsyncResult(callback, state); } -#if DOTNET5_4 +#if NETSTANDARD1_3 public void EndWrite(IAsyncResult asyncResult) #else public override void EndWrite(IAsyncResult asyncResult) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 43e9b6c027..dbb9f9e557 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -120,7 +120,7 @@ namespace Microsoft.Net.Http.Server var boundHandle = responseStream.RequestContext.Server.BoundHandle; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. -#if DOTNET5_4 +#if NETSTANDARD1_3 _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. #else // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. diff --git a/src/Microsoft.Net.Http.Server/WebListenerException.cs b/src/Microsoft.Net.Http.Server/WebListenerException.cs index 8920b3fd25..3c0cb7bb89 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerException.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerException.cs @@ -45,7 +45,7 @@ namespace Microsoft.Net.Http.Server : base(errorCode, message) { } -#if DOTNET5_4 +#if NETSTANDARD1_3 public int ErrorCode #else // the base class returns the HResult with this property diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs index 4a310df3bf..5b29a3bc4c 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if DOTNET5_4 +#if NETSTANDARD1_3 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 650cffcf86..aef2c8b323 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if DOTNET5_4 +#if NETSTANDARD1_3 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs index bb8a238cf1..89ded72c3a 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DOTNET5_4 +#if NETSTANDARD1_3 using System; using System.ComponentModel; diff --git a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs index 0aa12a91e5..989211c70c 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DOTNET5_4 +#if NETSTANDARD1_3 namespace System { diff --git a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs index 1d6c825a65..807bdd2a60 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if DOTNET5_4 +#if NETSTANDARD1_3 namespace System.Runtime.InteropServices { diff --git a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs index d890c46b3f..27a17a745c 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DOTNET5_4 +#if NETSTANDARD1_3 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 5b5861dd58..8d12e7b336 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -9,12 +9,14 @@ "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", - "nowarn": [ "CS1591" ], + "nowarn": [ + "CS1591" + ], "xmlDoc": true }, "frameworks": { "net451": {}, - "dotnet5.4": { + "netstandard1.3": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.1-*", "System.Diagnostics.Contracts": "4.0.1-*", @@ -29,7 +31,10 @@ "System.Security.Principal.Windows": "4.0.0-*", "System.Text.Encoding.Extensions": "4.0.11-*", "System.Threading.Overlapped": "4.0.1-*" - } + }, + "imports": [ + "dotnet5.4" + ] } } } \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs index 8b81c7cd96..43c86e1fa2 100644 --- a/src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs @@ -31,7 +31,7 @@ namespace Microsoft.Net.WebSockets { internal static class UnsafeNativeMethods { -#if DOTNET5_4 +#if NETSTANDARD1_3 private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll"; #else private const string KERNEL32 = "kernel32.dll"; @@ -40,14 +40,14 @@ namespace Microsoft.Net.WebSockets internal static class SafeNetHandles { -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, CharSet=CharSet.Unicode, SetLastError = true)] #endif internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); -#if DOTNET5_4 +#if NETSTANDARD1_3 [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] #else [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] @@ -173,7 +173,7 @@ namespace Microsoft.Net.WebSockets static WebSocketProtocolComponent() { -#if DOTNET5_4 +#if NETSTANDARD1_3 DllFileName = Path.Combine(Environment.GetEnvironmentVariable("SYSTEMROOT"), "System32", WEBSOCKET); #else DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs index 6629e35271..1526acd056 100644 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs +++ b/src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs @@ -1103,7 +1103,7 @@ namespace Microsoft.Net.WebSockets if (thisLockTaken || sessionHandleLockTaken) { -#if !DOTNET5_4 +#if !NETSTANDARD1_3 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -1189,7 +1189,7 @@ namespace Microsoft.Net.WebSockets Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); if (lockTaken) { -#if !DOTNET5_4 +#if !NETSTANDARD1_3 RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -2253,7 +2253,7 @@ namespace Microsoft.Net.WebSockets "'webSocket.m_KeepAliveTracker' MUST NOT be NULL at this point."); int keepAliveIntervalMilliseconds = (int)_keepAliveInterval.TotalMilliseconds; Contract.Assert(keepAliveIntervalMilliseconds > 0, "'keepAliveIntervalMilliseconds' MUST be POSITIVE."); -#if DOTNET5_4 +#if NETSTANDARD1_3 _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); #else if (ExecutionContext.IsFlowSuppressed()) diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs index 0ae7e4bb89..a906a5d6aa 100644 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs +++ b/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; namespace Microsoft.Net.WebSockets { -#if !DOTNET5_4 +#if !NETSTANDARD1_3 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] #endif internal sealed class WebSocketException : Win32Exception @@ -115,7 +115,7 @@ namespace Microsoft.Net.WebSockets : base(message, innerException) { } -#if !DOTNET5_4 +#if !NETSTANDARD1_3 public override int ErrorCode { get diff --git a/src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index 650cffcf86..aef2c8b323 100644 --- a/src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -21,7 +21,7 @@ // // ==--== -#if DOTNET5_4 +#if NETSTANDARD1_3 namespace Microsoft.Win32.SafeHandles { diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs index b7f6eb4071..0345bbc1a1 100644 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs +++ b/src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if DOTNET5_4 +#if NETSTANDARD1_3 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs index 0aa12a91e5..989211c70c 100644 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs +++ b/src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DOTNET5_4 +#if NETSTANDARD1_3 namespace System { diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs index 1d6c825a65..807bdd2a60 100644 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ b/src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs @@ -31,7 +31,7 @@ ** =============================================================================*/ -#if DOTNET5_4 +#if NETSTANDARD1_3 namespace System.Runtime.InteropServices { diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs index d890c46b3f..27a17a745c 100644 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs +++ b/src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs @@ -21,7 +21,7 @@ // //------------------------------------------------------------------------------ -#if DOTNET5_4 +#if NETSTANDARD1_3 using System.Runtime.InteropServices; using System.Text; diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs index 023d53ffc9..3b4436eb4e 100644 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs +++ b/src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs @@ -15,7 +15,7 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if DOTNET5_4 +#if NETSTANDARD1_3 using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 7d83e64239..11497df423 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -8,12 +8,14 @@ "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", - "nowarn": [ "CS1591" ], + "nowarn": [ + "CS1591" + ], "xmlDoc": true }, "frameworks": { "net451": {}, - "dotnet5.4": { + "netstandard1.3": { "dependencies": { "System.Collections": "4.0.11-*", "System.Linq": "4.1.0-*", @@ -25,7 +27,10 @@ "System.Threading.Tasks": "4.0.11-*", "System.Threading.Timer": "4.0.1-*", "System.Threading.ThreadPool": "4.0.10-*" - } + }, + "imports": [ + "dotnet5.4" + ] } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index f11949a4e7..12944d9b8a 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal("Hello World", response); } } -#if !DNXCORE50 +#if !NETSTANDARDAPP1_5 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 4ec53b2a36..7242b3d17c 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if DNXCORE50 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETSTANDARDAPP1_5 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if DNXCORE50 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETSTANDARDAPP1_5 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 001a9e016a..3d671edbdf 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -7,14 +7,17 @@ "xunit": "2.1.0" }, "frameworks": { - "dnxcore50": { + "netstandardapp1.5": { "dependencies": { "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebHeaderCollection": "4.0.1-*", "dotnet-test-xunit": "1.0.0-dev-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dnxcore50", + "portable-net451+win8" + ] }, "net451": { "frameworkAssemblies": { @@ -27,4 +30,4 @@ } } } -} +} \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 39dc2adcbc..3b195b2fc2 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -153,7 +153,7 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#if !DNXCORE50 +#if !NETSTANDARDAPP1_5 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; @@ -175,7 +175,7 @@ namespace Microsoft.Net.Http.Server context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); -#if !DNXCORE50 +#if !NETSTANDARDAPP1_5 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; @@ -199,7 +199,7 @@ namespace Microsoft.Net.Http.Server context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); -#if !DNXCORE50 +#if !NETSTANDARDAPP1_5 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index ffaa2442d6..a3c29a0991 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Linq; @@ -217,7 +217,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if DNXCORE50 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETSTANDARDAPP1_5 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -246,7 +246,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if DNXCORE50 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETSTANDARDAPP1_5 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 9de25a8e0c..c1d87dfc0c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -123,7 +123,7 @@ namespace Microsoft.Net.Http.Server context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); -#if !DNXCORE50 +#if !NETSTANDARDAPP1_5 // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.GetContextAsync(); context.Abort(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 1abe854726..c5dd6a27b7 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -8,7 +8,7 @@ "xunit": "2.1.0" }, "frameworks": { - "dnxcore50": { + "netstandardapp1.5": { "dependencies": { "System.Net.Http": "4.0.1-*", "System.Net.Http.WinHttpHandler": "4.0.0-*", @@ -16,7 +16,10 @@ "System.Net.WebSockets.Client": "4.0.0-*", "dotnet-test-xunit": "1.0.0-dev-*" }, - "imports": "portable-net451+win8" + "imports": [ + "dnxcore50", + "portable-net451+win8" + ] }, "net451": { "frameworkAssemblies": { @@ -31,4 +34,4 @@ } } } -} +} \ No newline at end of file From d593ac148d173327d48f59abfb99fc44fb585754 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 2 Mar 2016 21:39:28 -0800 Subject: [PATCH 316/597] Remove project name from output path - aspnet/Coherence-Signed#187 - remove `` settings but maintain other unique aspects e.g. `` - in a few cases, standardize on VS version `14.0` and not something more specific --- samples/HelloWorld/HelloWorld.xproj | 2 +- samples/HotAddSample/HotAddSample.xproj | 2 +- samples/SelfHostServer/SelfHostServer.xproj | 2 +- .../Microsoft.AspNetCore.Server.WebListener.xproj | 2 +- src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj | 2 +- .../Microsoft.Net.WebSockets.Server.xproj | 2 +- ...icrosoft.AspNetCore.Server.WebListener.FunctionalTests.xproj | 2 +- .../Microsoft.Net.Http.Server.FunctionalTests.xproj | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/HelloWorld/HelloWorld.xproj b/samples/HelloWorld/HelloWorld.xproj index 839db9da9c..9172e56880 100644 --- a/samples/HelloWorld/HelloWorld.xproj +++ b/samples/HelloWorld/HelloWorld.xproj @@ -8,7 +8,7 @@ 6daf3e6b-8e1b-4e6e-b9fe-7b1e5fdb7db4 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/samples/HotAddSample/HotAddSample.xproj b/samples/HotAddSample/HotAddSample.xproj index efa6f91d2b..c65e2badf7 100644 --- a/samples/HotAddSample/HotAddSample.xproj +++ b/samples/HotAddSample/HotAddSample.xproj @@ -8,7 +8,7 @@ 8bfa392a-8b67-4454-916b-67c545edfaef ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/samples/SelfHostServer/SelfHostServer.xproj b/samples/SelfHostServer/SelfHostServer.xproj index c3d8c1b6de..31317b6e61 100644 --- a/samples/SelfHostServer/SelfHostServer.xproj +++ b/samples/SelfHostServer/SelfHostServer.xproj @@ -8,7 +8,7 @@ 1236f93a-ac5c-4a77-9477-c88f040151ca ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj b/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj index cba373f53a..0ce3b5dc6d 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj +++ b/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj @@ -8,7 +8,7 @@ b9f45f9d-d206-47f0-8e5f-54ce2f0bdf92 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj index 9966c5c657..24b618f386 100644 --- a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj +++ b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj @@ -8,7 +8,7 @@ 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj b/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj index bfc3ead68e..e2db8f32c7 100644 --- a/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj +++ b/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj @@ -8,7 +8,7 @@ e788aeae-2cb4-4bfa-8746-d0bb7e93a1bb ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj index a7ac76a466..b172408b11 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj @@ -8,7 +8,7 @@ 4492ff4c-9032-411d-853f-46b01755e504 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj index 185d583692..db2158c7ca 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj @@ -8,7 +8,7 @@ dcb6e0b1-223d-44e6-8696-4767e5b6e6a1 ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\$(MSBuildProjectName)\ + ..\..\artifacts\bin\ 2.0 From 9e20f6fa0e34aa5beb7564d941c6853814d9878b Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 3 Mar 2016 05:43:33 -0800 Subject: [PATCH 317/597] Fix build break --- src/Microsoft.Net.Http.Server/project.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 8d12e7b336..52e4499c32 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -15,7 +15,11 @@ "xmlDoc": true }, "frameworks": { - "net451": {}, + "net451": { + "frameworkAssemblies": { + "System.Runtime": { "type": "build" } + } + }, "netstandard1.3": { "dependencies": { "Microsoft.Win32.Primitives": "4.0.1-*", From d6d43047b14fbd6cbc88f81c3beedde1b9ead8f1 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Thu, 3 Mar 2016 17:32:46 -0800 Subject: [PATCH 318/597] Added Company, Copyright and Product attributes to AssemblyInfo --- .../Properties/AssemblyInfo.cs | 5 ++++- src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs | 4 +++- .../Properties/AssemblyInfo.cs | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs index 78dfe3c1e0..79eeb571ef 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs @@ -5,4 +5,7 @@ using System.Reflection; using System.Resources; [assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs index 78dfe3c1e0..ed2f43e9e7 100644 --- a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs @@ -5,4 +5,6 @@ using System.Reflection; using System.Resources; [assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] diff --git a/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs index 78dfe3c1e0..ed2f43e9e7 100644 --- a/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs @@ -5,4 +5,6 @@ using System.Reflection; using System.Resources; [assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] From 0896ac4f95941b5a499741218b68d3b661874bf9 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Thu, 3 Mar 2016 17:53:04 -0800 Subject: [PATCH 319/597] Added missed attributes --- src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs | 1 + src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs index ed2f43e9e7..79eeb571ef 100644 --- a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs @@ -8,3 +8,4 @@ using System.Resources; [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyCompany("Microsoft Corporation.")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs index ed2f43e9e7..79eeb571ef 100644 --- a/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs @@ -8,3 +8,4 @@ using System.Resources; [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyCompany("Microsoft Corporation.")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] From 27742594617edd8a7807c5f582021c3424bae6a0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 7 Mar 2016 11:13:15 -0800 Subject: [PATCH 320/597] React to test regression in HttpResponseMessage.ReasonPhrase. --- .../ResponseTests.cs | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs index ad63957536..7203688118 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(901, (int)response.StatusCode); - Assert.Equal(string.Empty, response.ReasonPhrase); + Assert.True(string.IsNullOrEmpty(response.ReasonPhrase)); // https://github.com/dotnet/corefx/issues/6721 Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs index 4e46f19ef7..e2266b330f 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs @@ -87,7 +87,7 @@ namespace Microsoft.Net.Http.Server HttpResponseMessage response = await responseTask; Assert.Equal(901, (int)response.StatusCode); - Assert.Equal(string.Empty, response.ReasonPhrase); + Assert.True(string.IsNullOrEmpty(response.ReasonPhrase)); // https://github.com/dotnet/corefx/issues/6721 Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); } } From f11c5aef237a34cc3a4fd294847ae7f4a8a523d0 Mon Sep 17 00:00:00 2001 From: Victor Hurdugaci Date: Mon, 7 Mar 2016 20:55:00 -0800 Subject: [PATCH 321/597] Update the build scripts to the latest version --- build.ps1 | 33 ++++++++++++++++++++++++++++++++- build.sh | 15 +++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/build.ps1 b/build.ps1 index 4fd24a30d5..8f2f99691a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,33 @@ +$ErrorActionPreference = "Stop" + +function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +{ + while($true) + { + try + { + Invoke-WebRequest $url -OutFile $downloadLocation + break + } + catch + { + $exceptionMessage = $_.Exception.Message + Write-Host "Failed to download '$url': $exceptionMessage" + if ($retries -gt 0) { + $retries-- + Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" + Start-Sleep -Seconds 10 + + } + else + { + $exception = $_.Exception + throw $exception + } + } + } +} + cd $PSScriptRoot $repoFolder = $PSScriptRoot @@ -20,7 +50,8 @@ if (!(Test-Path $buildFolder)) { $localZipFile="$tempFolder\korebuild.zip" - Invoke-WebRequest $koreBuildZip -OutFile $localZipFile + DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 + Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) diff --git a/build.sh b/build.sh index 79638d06b6..f4208100eb 100755 --- a/build.sh +++ b/build.sh @@ -18,7 +18,18 @@ if test ! -d $buildFolder; then localZipFile="$tempFolder/korebuild.zip" - wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip /dev/null + retries=6 + until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) + do + echo "Failed to download '$koreBuildZip'" + if [ "$retries" -le 0 ]; then + exit 1 + fi + retries=$((retries - 1)) + echo "Waiting 10 seconds before retrying. Retries left: $retries" + sleep 10s + done + unzip -q -d $tempFolder $localZipFile mkdir $buildFolder @@ -32,4 +43,4 @@ if test ! -d $buildFolder; then fi fi -$buildFile -r $repoFolder "$@" +$buildFile -r $repoFolder "$@" \ No newline at end of file From 86af69d2d714318bb2eec6fde26f9d612fb06f39 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Mon, 8 Feb 2016 10:26:44 -0800 Subject: [PATCH 322/597] Adapt samples to .NET Core. --- samples/HelloWorld/Program.cs | 7 ++++++- samples/HelloWorld/project.json | 14 ++++++-------- samples/HotAddSample/Startup.cs | 6 ++++-- samples/HotAddSample/hosting.json | 4 ---- samples/HotAddSample/project.json | 8 +++++--- samples/SelfHostServer/Startup.cs | 1 + samples/SelfHostServer/hosting.json | 4 ---- samples/SelfHostServer/project.json | 8 +++++--- 8 files changed, 27 insertions(+), 25 deletions(-) delete mode 100644 samples/HotAddSample/hosting.json delete mode 100644 samples/SelfHostServer/hosting.json diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 7b545803e9..0285c349fa 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -9,7 +9,12 @@ namespace HelloWorld { public class Program { - public static async Task Main(string[] args) + public static void Main(string[] args) + { + Run(args).Wait(); + } + + public static async Task Run(string[] args) { using (WebListener listener = new WebListener()) { diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 2d80d1f40d..495007ebed 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,21 +1,19 @@ { + "compilationOptions": { + "emitEntryPoint": true + }, "dependencies": { "Microsoft.Net.Http.Server": "0.1.0-*", - "Microsoft.Net.WebSockets.Server": "0.1.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.Net.WebSockets.Server": "0.1.0-*" }, "commands": { "sample": "HelloWorld" }, "frameworks": { - "dnx451": {}, + "net451": {}, "netstandardapp1.5": { "dependencies": { - "System.Collections": "4.0.11-*", - "System.Console": "4.0.0-*", - "System.Globalization": "4.0.11-*", - "System.IO": "4.1.0-*", - "System.Threading.Tasks": "4.0.11-*" + "NETStandard.Library": "1.0.0-*" }, "imports": [ "dnxcore50" diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index d2ef0cbfd0..da67990715 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Features; using Microsoft.Extensions.Logging; +using Microsoft.Net.Http.Server; namespace HotAddSample { @@ -17,7 +18,7 @@ namespace HotAddSample { loggerfactory.AddConsole(LogLevel.Information); - var addresses = app.ServerFeatures.Get().Addresses; + var addresses = app.ServerFeatures.Get().UrlPrefixes; addresses.Add("http://localhost:12346/pathBase/"); app.Use(async (context, next) => @@ -31,7 +32,7 @@ namespace HotAddSample try { addresses.Add(toAdd); - await context.Response.WriteAsync("Added: " + toAdd); + await context.Response.WriteAsync("Added: " + toAdd + ""); } catch (Exception ex) { @@ -93,6 +94,7 @@ namespace HotAddSample var host = new WebHostBuilder() .UseDefaultConfiguration(args) .UseStartup() + .UseServer("Microsoft.AspNetCore.Server.WebListener") .Build(); host.Run(); diff --git a/samples/HotAddSample/hosting.json b/samples/HotAddSample/hosting.json deleted file mode 100644 index 598af3d3a8..0000000000 --- a/samples/HotAddSample/hosting.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "server": "Microsoft.AspNetCore.Server.WebListener", - "server.urls": "http://localhost:12345" -} diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index dde0f7325a..307ed54a6d 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -2,8 +2,7 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "compilationOptions": { "emitEntryPoint": true @@ -12,8 +11,11 @@ "web": "HotAddSample" }, "frameworks": { - "dnx451": {}, + "net451": {}, "netstandardapp1.5": { + "dependencies": { + "NETStandard.Library": "1.0.0-*" + }, "imports": [ "dnxcore50" ] diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 9ee6194f07..36b3c7f29c 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -43,6 +43,7 @@ namespace SelfHostServer var host = new WebHostBuilder() .UseDefaultConfiguration(args) .UseStartup() + .UseServer("Microsoft.AspNetCore.Server.WebListener") .Build(); host.Run(); diff --git a/samples/SelfHostServer/hosting.json b/samples/SelfHostServer/hosting.json deleted file mode 100644 index c1733ee469..0000000000 --- a/samples/SelfHostServer/hosting.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "server": "Microsoft.AspNetCore.Server.WebListener", - "server.urls": "http://localhost:8080" -} diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index e31b464c7b..d2eccfeff3 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,8 +1,7 @@ { "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "compilationOptions": { "emitEntryPoint": true @@ -11,8 +10,11 @@ "web": "SelfHostServer" }, "frameworks": { - "dnx451": {}, + "net451": {}, "netstandardapp1.5": { + "dependencies": { + "NETStandard.Library": "1.0.0-*" + }, "imports": [ "dnxcore50" ] From 5437259956c2ab3b9513f471c5a2bedc64e6e65f Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 9 Mar 2016 16:35:05 -0800 Subject: [PATCH 323/597] Limit the branches that build on our public CI. [ci skip] --- .travis.yml | 6 ++++++ appveyor.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index bf811dc26a..dd4686f39c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,5 +16,11 @@ os: - linux - osx osx_image: xcode7.1 +branches: + only: + - master + - release + - dev + - /^(.*\\/)?ci-.*$/ script: - ./build.sh verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 3fab83e134..c6d5f7d997 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,11 @@ init: - git config --global core.autocrlf true +branches: + only: + - master + - release + - dev + - /^(.*\\/)?ci-.*$/ build_script: - build.cmd verify clone_depth: 1 From 02f30afc0ee3c24ce7566d421009cf9a353c39cd Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 9 Mar 2016 17:44:48 -0800 Subject: [PATCH 324/597] Fix backslashes in yml config. [ci skip] --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd4686f39c..df22f7a880 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,6 @@ branches: - master - release - dev - - /^(.*\\/)?ci-.*$/ + - /^(.*\/)?ci-.*$/ script: - ./build.sh verify \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index c6d5f7d997..b9a9bcd1e6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ branches: - master - release - dev - - /^(.*\\/)?ci-.*$/ + - /^(.*\/)?ci-.*$/ build_script: - build.cmd verify clone_depth: 1 From 4052c26a73fbb80cd3118c6eb66d532e7c86a4fd Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 22 Mar 2016 10:33:56 -0700 Subject: [PATCH 325/597] Quick fix: Clean up `HeaderDictionary` doc comments - remove incorrect use of `Microsoft.AspNetCore.Http.Internal` namespace --- .../HeaderDictionary.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs b/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs index b71a1bd876..6676fd8b99 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs @@ -144,7 +144,8 @@ namespace Microsoft.AspNetCore.Server.WebListener /// /// Copies the elements to a one-dimensional Array instance at the specified index. /// - /// The one-dimensional Array that is the destination of the specified objects copied from the . + /// The one-dimensional Array that is the destination of the specified objects copied from + /// the . /// The zero-based index in at which copying begins. public void CopyTo(KeyValuePair[] array, int arrayIndex) { @@ -185,7 +186,7 @@ namespace Microsoft.AspNetCore.Server.WebListener /// /// Returns an enumerator that iterates through a collection. /// - /// An object that can be used to iterate through the collection. + /// An object that can be used to iterate through the collection. public IEnumerator GetEnumerator() { return Store.GetEnumerator(); @@ -194,7 +195,7 @@ namespace Microsoft.AspNetCore.Server.WebListener /// /// Returns an enumerator that iterates through a collection. /// - /// An object that can be used to iterate through the collection. + /// An object that can be used to iterate through the collection. IEnumerator> IEnumerable>.GetEnumerator() { return Store.GetEnumerator(); From 7314e6568af37613f4993b8a29a46b6f96bb48a1 Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 22 Mar 2016 11:42:20 -0700 Subject: [PATCH 326/597] Reacting to Hosting changes --- samples/HotAddSample/Startup.cs | 2 +- samples/SelfHostServer/Startup.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index da67990715..0a37ddf937 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -92,7 +92,7 @@ namespace HotAddSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseDefaultConfiguration(args) + .UseDefaultHostingConfiguration(args) .UseStartup() .UseServer("Microsoft.AspNetCore.Server.WebListener") .Build(); diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 36b3c7f29c..e10079e497 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -41,7 +41,7 @@ namespace SelfHostServer public static void Main(string[] args) { var host = new WebHostBuilder() - .UseDefaultConfiguration(args) + .UseDefaultHostingConfiguration(args) .UseStartup() .UseServer("Microsoft.AspNetCore.Server.WebListener") .Build(); From 7c67a4a594890c03342bb0008584611c02035cc7 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Fri, 25 Mar 2016 09:25:04 -0700 Subject: [PATCH 327/597] Fixed packages --- .../project.json | 5 +++-- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 3d671edbdf..351c9359fc 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -3,7 +3,6 @@ "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "frameworks": { @@ -12,7 +11,9 @@ "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebHeaderCollection": "4.0.1-*", - "dotnet-test-xunit": "1.0.0-dev-*" + "dotnet-test-xunit": "1.0.0-dev-*", + "NETStandard.Library": "1.5.0-*", + "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ "dnxcore50", diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index c5dd6a27b7..7c29176861 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -4,7 +4,6 @@ "Microsoft.Net.Http.Server": "0.1.0-*", "Microsoft.Net.WebSockets.Server": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" }, "frameworks": { @@ -14,7 +13,9 @@ "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebSockets.Client": "4.0.0-*", - "dotnet-test-xunit": "1.0.0-dev-*" + "dotnet-test-xunit": "1.0.0-dev-*", + "NETStandard.Library": "1.5.0-*", + "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ "dnxcore50", From f0a5a01f6d9c0e90c43f485e7337d5c2bd818f21 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Fri, 25 Mar 2016 10:04:17 -0700 Subject: [PATCH 328/597] React to `HttpContextFactory` constructor change - remove unused field - see pull aspnet/HttpAbstractions#594 and issue aspnet/HttpAbstractions#561 --- .../Utilities.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs index 97521f74bd..689a0ed98e 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs @@ -18,8 +18,6 @@ using System; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Internal; using Microsoft.AspNetCore.Server.Features; using Microsoft.Net.Http.Server; @@ -27,14 +25,13 @@ namespace Microsoft.AspNetCore.Server.WebListener { internal static class Utilities { - // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free - // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in + // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free + // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in // Microsoft.Net.Http.Server. private const int BasePort = 5001; private const int MaxPort = 8000; private static int NextPort = BasePort; private static object PortLock = new object(); - private static IHttpContextFactory Factory = new HttpContextFactory(new HttpContextAccessor()); internal static IServer CreateHttpServer(out string baseAddress, RequestDelegate app) { From faeedf1c42773605a6055b8692331dc7d59a2fb8 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 30 Mar 2016 15:40:45 -0700 Subject: [PATCH 329/597] Update samples --- samples/HelloWorld/project.json | 5 +++-- samples/HotAddSample/project.json | 5 +++-- samples/SelfHostServer/project.json | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 495007ebed..f1daae728c 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -4,7 +4,8 @@ }, "dependencies": { "Microsoft.Net.Http.Server": "0.1.0-*", - "Microsoft.Net.WebSockets.Server": "0.1.0-*" + "Microsoft.Net.WebSockets.Server": "0.1.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "commands": { "sample": "HelloWorld" @@ -13,7 +14,7 @@ "net451": {}, "netstandardapp1.5": { "dependencies": { - "NETStandard.Library": "1.0.0-*" + "NETStandard.Library": "1.5.0-*" }, "imports": [ "dnxcore50" diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 307ed54a6d..d7c37ec446 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -2,7 +2,8 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "compilationOptions": { "emitEntryPoint": true @@ -14,7 +15,7 @@ "net451": {}, "netstandardapp1.5": { "dependencies": { - "NETStandard.Library": "1.0.0-*" + "NETStandard.Library": "1.5.0-*" }, "imports": [ "dnxcore50" diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index d2eccfeff3..b662bed05f 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,8 @@ { "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*", + "Microsoft.NETCore.Platforms": "1.0.1-*" }, "compilationOptions": { "emitEntryPoint": true @@ -13,7 +14,7 @@ "net451": {}, "netstandardapp1.5": { "dependencies": { - "NETStandard.Library": "1.0.0-*" + "NETStandard.Library": "1.5.0-*" }, "imports": [ "dnxcore50" From bdcdf29ade2be6242038491b2e77d813796a1878 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 30 Mar 2016 16:03:04 -0700 Subject: [PATCH 330/597] #182 Revert workaround for HttpResponseMessage.ReasonPhrase. --- .../ResponseTests.cs | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs index 7203688118..ad63957536 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { HttpResponseMessage response = await SendRequestAsync(address); Assert.Equal(901, (int)response.StatusCode); - Assert.True(string.IsNullOrEmpty(response.ReasonPhrase)); // https://github.com/dotnet/corefx/issues/6721 + Assert.Equal(string.Empty, response.ReasonPhrase); Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs index e2266b330f..4e46f19ef7 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs @@ -87,7 +87,7 @@ namespace Microsoft.Net.Http.Server HttpResponseMessage response = await responseTask; Assert.Equal(901, (int)response.StatusCode); - Assert.True(string.IsNullOrEmpty(response.ReasonPhrase)); // https://github.com/dotnet/corefx/issues/6721 + Assert.Equal(string.Empty, response.ReasonPhrase); Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); } } From 84c897543ec86b3c0a0c002407149582dc8652a5 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sun, 27 Mar 2016 12:18:05 -0700 Subject: [PATCH 331/597] React to HttpAbstractions namespace changes - aspnet/HttpAbstractions#549 and aspnet/HttpAbstractions#592 - clean up `using`s --- .../DummyApplication.cs | 1 - .../RequestBodyTests.cs | 2 -- .../RequestHeaderTests.cs | 2 -- .../ResponseBodyTests.cs | 3 --- .../ResponseCachingTests.cs | 2 -- .../ResponseTests.cs | 1 - 6 files changed, 11 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs index a8863fbaf2..4ef9a8d2e0 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs @@ -20,7 +20,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Internal; namespace Microsoft.AspNetCore.Server.WebListener { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 12944d9b8a..3e140a9ec8 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -23,8 +23,6 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Internal; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index d6da222f14..3ff2c613f6 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -20,8 +20,6 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Internal; using Microsoft.Extensions.Primitives; using Xunit; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index b87a5fbfcb..7f6122dccc 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -23,9 +23,6 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Internal; -using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index 70b44128e3..bcddd3be7a 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -4,8 +4,6 @@ using System; using System.Linq; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Internal; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs index ad63957536..51aeb4a053 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -20,7 +20,6 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Internal; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener From 269380e651105493bba34476c922d475a15c0f01 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Fri, 1 Apr 2016 11:57:13 -0700 Subject: [PATCH 332/597] React to logging changes --- src/Microsoft.Net.Http.Server/LogHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index 7ac8e13957..4d4816462e 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -89,7 +89,7 @@ namespace Microsoft.Net.Http.Server private class NullLogger : ILogger { - public IDisposable BeginScopeImpl(object state) + public IDisposable BeginScope(TState state) { return new NullDispose(); } From cd5173c574697ba1bb4286414211e365f176a5a5 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 6 Apr 2016 09:46:56 -0700 Subject: [PATCH 333/597] Updating to release. --- NuGet.config | 2 +- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NuGet.config b/NuGet.config index 1707938c61..9db87a421e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..cf8bff13bb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..f88fe4052e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 3af81ac386e8dd4a9f5cc36da7d82c64dd41d165 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 6 Apr 2016 18:25:02 -0700 Subject: [PATCH 334/597] Fix versions --- src/Microsoft.Net.Http.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 52e4499c32..12ac27494a 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -31,7 +31,7 @@ "System.Net.Primitives": "4.0.11-*", "System.Runtime.InteropServices": "4.1.0-*", "System.Security.Claims": "4.0.1-*", - "System.Security.Cryptography.X509Certificates": "4.0.0-*", + "System.Security.Cryptography.X509Certificates": "4.1.0-*", "System.Security.Principal.Windows": "4.0.0-*", "System.Text.Encoding.Extensions": "4.0.11-*", "System.Threading.Overlapped": "4.0.1-*" From 5aaed04bcd8ba5961226d6ef66708973d64e3009 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 6 Apr 2016 19:24:25 -0700 Subject: [PATCH 335/597] Fixing build break --- src/Microsoft.Net.Http.Server/project.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 12ac27494a..bbcef72d03 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -29,11 +29,13 @@ "System.IO": "4.1.0-*", "System.IO.FileSystem": "4.0.1-*", "System.Net.Primitives": "4.0.11-*", + "System.Runtime.Extensions": "4.1.0-*", "System.Runtime.InteropServices": "4.1.0-*", "System.Security.Claims": "4.0.1-*", "System.Security.Cryptography.X509Certificates": "4.1.0-*", "System.Security.Principal.Windows": "4.0.0-*", "System.Text.Encoding.Extensions": "4.0.11-*", + "System.Threading": "4.0.11-*", "System.Threading.Overlapped": "4.0.1-*" }, "imports": [ From 5fd4db5e21fa844cf7de71f113d461ce01cb5b8a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 7 Apr 2016 12:32:08 -0700 Subject: [PATCH 336/597] Fix System.Security.Cryptography.Algorithms version --- src/Microsoft.Net.WebSockets.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 11497df423..7bc27068fa 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -22,7 +22,7 @@ "System.Net.WebSockets": "4.0.0-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", - "System.Security.Cryptography.Algorithms": "4.0.0-*", + "System.Security.Cryptography.Algorithms": "4.1.0-*", "System.Threading": "4.0.11-*", "System.Threading.Tasks": "4.0.11-*", "System.Threading.Timer": "4.0.1-*", From 316fbccd1eadda993a472f599dadaea8d6f9b86a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 7 Apr 2016 15:39:40 -0700 Subject: [PATCH 337/597] Removing imports from src projects --- src/Microsoft.AspNetCore.Server.WebListener/project.json | 1 - src/Microsoft.Net.Http.Server/project.json | 9 ++++----- src/Microsoft.Net.WebSockets.Server/project.json | 5 +---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index b2a504e17f..03d3aa25b8 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -22,7 +22,6 @@ "System.Security.Claims": "4.0.1-*" }, "imports": [ - "dotnet5.4", "portable-net451+win8" ] } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index bbcef72d03..bfe06275c5 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -17,7 +17,9 @@ "frameworks": { "net451": { "frameworkAssemblies": { - "System.Runtime": { "type": "build" } + "System.Runtime": { + "type": "build" + } } }, "netstandard1.3": { @@ -37,10 +39,7 @@ "System.Text.Encoding.Extensions": "4.0.11-*", "System.Threading": "4.0.11-*", "System.Threading.Overlapped": "4.0.1-*" - }, - "imports": [ - "dotnet5.4" - ] + } } } } \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 7bc27068fa..99416df264 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -27,10 +27,7 @@ "System.Threading.Tasks": "4.0.11-*", "System.Threading.Timer": "4.0.1-*", "System.Threading.ThreadPool": "4.0.10-*" - }, - "imports": [ - "dotnet5.4" - ] + } } } } \ No newline at end of file From 75144a4350dedc34705bec2864a6ddedb78425da Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 14 Apr 2016 15:24:10 -0700 Subject: [PATCH 338/597] Migrate tests, tools and samples to portable --- samples/HelloWorld/project.json | 10 ++++++---- samples/HotAddSample/project.json | 10 ++++++---- samples/SelfHostServer/project.json | 10 ++++++---- .../RequestBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 4 ++-- .../project.json | 7 +++++-- .../ResponseBodyTests.cs | 6 +++--- .../ResponseHeaderTests.cs | 4 ++-- .../ServerTests.cs | 2 +- .../project.json | 7 +++++-- 10 files changed, 37 insertions(+), 25 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index f1daae728c..ff0fe111a8 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -4,17 +4,19 @@ }, "dependencies": { "Microsoft.Net.Http.Server": "0.1.0-*", - "Microsoft.Net.WebSockets.Server": "0.1.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.Net.WebSockets.Server": "0.1.0-*" }, "commands": { "sample": "HelloWorld" }, "frameworks": { "net451": {}, - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { - "NETStandard.Library": "1.5.0-*" + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } }, "imports": [ "dnxcore50" diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index d7c37ec446..36d50c8f32 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -2,8 +2,7 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "compilationOptions": { "emitEntryPoint": true @@ -13,9 +12,12 @@ }, "frameworks": { "net451": {}, - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { - "NETStandard.Library": "1.5.0-*" + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } }, "imports": [ "dnxcore50" diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index b662bed05f..471564e28b 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,8 +1,7 @@ { "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "compilationOptions": { "emitEntryPoint": true @@ -12,9 +11,12 @@ }, "frameworks": { "net451": {}, - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { - "NETStandard.Library": "1.5.0-*" + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } }, "imports": [ "dnxcore50" diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 3e140a9ec8..62bd825730 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal("Hello World", response); } } -#if !NETSTANDARDAPP1_5 +#if !NETCOREAPP1_0 [Fact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 7242b3d17c..9d31c385b5 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETSTANDARDAPP1_5 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETSTANDARDAPP1_5 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 351c9359fc..7592527454 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -6,13 +6,16 @@ "xunit": "2.1.0" }, "frameworks": { - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + }, "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebHeaderCollection": "4.0.1-*", "dotnet-test-xunit": "1.0.0-dev-*", - "NETStandard.Library": "1.5.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 3b195b2fc2..9b990f777c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -153,7 +153,7 @@ namespace Microsoft.Net.Http.Server var context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#if !NETSTANDARDAPP1_5 +#if !NETCOREAPP1_0 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; @@ -175,7 +175,7 @@ namespace Microsoft.Net.Http.Server context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); -#if !NETSTANDARDAPP1_5 +#if !NETCOREAPP1_0 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; @@ -199,7 +199,7 @@ namespace Microsoft.Net.Http.Server context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); -#if !NETSTANDARDAPP1_5 +#if !NETCOREAPP1_0 // HttpClient retries the request because it didn't get a response. context = await server.GetContextAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index a3c29a0991..3a498ecbda 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -217,7 +217,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETSTANDARDAPP1_5 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -246,7 +246,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETSTANDARDAPP1_5 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index c1d87dfc0c..eebf509011 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -123,7 +123,7 @@ namespace Microsoft.Net.Http.Server context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); -#if !NETSTANDARDAPP1_5 +#if !NETCOREAPP1_0 // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.GetContextAsync(); context.Abort(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 7c29176861..159b5be103 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -7,14 +7,17 @@ "xunit": "2.1.0" }, "frameworks": { - "netstandardapp1.5": { + "netcoreapp1.0": { "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + }, "System.Net.Http": "4.0.1-*", "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebSockets.Client": "4.0.0-*", "dotnet-test-xunit": "1.0.0-dev-*", - "NETStandard.Library": "1.5.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ From ff95748d7e896d6d48f817891c052cea38fce1f5 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 15 Apr 2016 16:08:54 -0700 Subject: [PATCH 339/597] Hosting#698 Remove IServerFactory, add UseWebListener extension --- samples/HotAddSample/Startup.cs | 4 +- samples/SelfHostServer/Startup.cs | 8 +- .../Internal/WebListenerOptionsSetup.cs | 38 ++++++++ .../MessagePump.cs | 36 ++++---- .../ServerFactory.cs | 89 ------------------- .../WebHostBuilderWebListenerExtensions.cs | 69 ++++++++++++++ ...ressesFeature.cs => WebListenerOptions.cs} | 10 ++- .../RequestTests.cs | 8 +- .../ServerTests.cs | 10 +-- .../Utilities.cs | 15 ++-- 10 files changed, 154 insertions(+), 133 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs delete mode 100644 src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs create mode 100644 src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs rename src/Microsoft.AspNetCore.Server.WebListener/{ServerAddressesFeature.cs => WebListenerOptions.cs} (72%) diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index 0a37ddf937..bfa147d918 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Server.Features; +using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; @@ -94,7 +94,7 @@ namespace HotAddSample var host = new WebHostBuilder() .UseDefaultHostingConfiguration(args) .UseStartup() - .UseServer("Microsoft.AspNetCore.Server.WebListener") + .UseWebListener() .Build(); host.Run(); diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index e10079e497..0e276faca8 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -15,9 +15,6 @@ namespace SelfHostServer { public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { - var listener = app.ServerFeatures.Get(); - listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; - loggerfactory.AddConsole(LogLevel.Debug); app.Run(async context => @@ -43,7 +40,10 @@ namespace SelfHostServer var host = new WebHostBuilder() .UseDefaultHostingConfiguration(args) .UseStartup() - .UseServer("Microsoft.AspNetCore.Server.WebListener") + .UseWebListener(options => + { + options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; + }) .Build(); host.Run(); diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs b/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs new file mode 100644 index 0000000000..5e27bbf8c2 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Server.WebListener.Internal +{ + public class WebListenerOptionsSetup : IConfigureOptions + { + private ILoggerFactory _loggerFactory; + + public WebListenerOptionsSetup(ILoggerFactory loggerFactory) + { + _loggerFactory = loggerFactory; + } + + public void Configure(WebListenerOptions options) + { + options.Listener = new Microsoft.Net.Http.Server.WebListener(_loggerFactory); + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs index cb2bca862d..554a090c8d 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs @@ -21,14 +21,15 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Server.Features; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Net.Http.Server; namespace Microsoft.AspNetCore.Server.WebListener { - internal class MessagePump : IServer + public class MessagePump : IServer { private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; @@ -44,25 +45,32 @@ namespace Microsoft.AspNetCore.Server.WebListener private bool _stopping; private int _outstandingRequests; private ManualResetEvent _shutdownSignal; - - internal MessagePump(Microsoft.Net.Http.Server.WebListener listener, ILoggerFactory loggerFactory, IFeatureCollection features) + + private readonly ServerAddressesFeature _serverAddresses; + + public MessagePump(IOptions options, ILoggerFactory loggerFactory) { - if (features == null) + if (options == null) { - throw new ArgumentNullException(nameof(features)); + throw new ArgumentNullException(nameof(options)); + } + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); } - Contract.Assert(listener != null); - _listener = listener; + _listener = options.Value?.Listener ?? new Microsoft.Net.Http.Server.WebListener(loggerFactory); _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); - Features = features; + Features = new FeatureCollection(); + _serverAddresses = new ServerAddressesFeature(); + Features.Set(_serverAddresses); _processRequest = new Action(ProcessRequestAsync); _maxAccepts = DefaultMaxAccepts; _shutdownSignal = new ManualResetEvent(false); } - internal Microsoft.Net.Http.Server.WebListener Listener + public Microsoft.Net.Http.Server.WebListener Listener { get { return _listener; } } @@ -94,13 +102,7 @@ namespace Microsoft.AspNetCore.Server.WebListener throw new ArgumentNullException(nameof(application)); } - var addressesFeature = Features.Get(); - if (addressesFeature == null) - { - throw new InvalidOperationException($"{nameof(IServerAddressesFeature)} is missing."); - } - - ParseAddresses(addressesFeature.Addresses, Listener); + ParseAddresses(_serverAddresses.Addresses, Listener); // Can't call Start twice Contract.Assert(_application == null); diff --git a/src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs b/src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs deleted file mode 100644 index b37bfb7dd8..0000000000 --- a/src/Microsoft.AspNetCore.Server.WebListener/ServerFactory.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- -// Copyright 2011-2012 Katana contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using System; -using System.Diagnostics.CodeAnalysis; -using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Server.Features; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Server.WebListener -{ - /// - /// Implements the setup process for this server. - /// - public class ServerFactory : IServerFactory - { - private ILoggerFactory _loggerFactory; - - public ServerFactory(ILoggerFactory loggerFactory) - { - _loggerFactory = loggerFactory; - } - - /// - /// Creates a configurable instance of the server. - /// - /// - /// The server. Invoke Dispose to shut down. - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by caller")] - public IServer CreateServer(IConfiguration configuration) - { - Microsoft.Net.Http.Server.WebListener listener = new Microsoft.Net.Http.Server.WebListener(_loggerFactory); - var serverFeatures = new FeatureCollection(); - serverFeatures.Set(listener); - serverFeatures.Set(SplitAddresses(configuration)); - - return new MessagePump(listener, _loggerFactory, serverFeatures); - } - - private IServerAddressesFeature SplitAddresses(IConfiguration config) - { - var addressesFeature = new ServerAddressesFeature(); - if (config != null && !string.IsNullOrEmpty(config["server.urls"])) - { - var urls = config["server.urls"]; - foreach (var value in urls.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) - { - addressesFeature.Addresses.Add(value); - } - } - return addressesFeature; - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs new file mode 100644 index 0000000000..f2cfe9deb2 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Server.WebListener; +using Microsoft.AspNetCore.Server.WebListener.Internal; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Hosting +{ + public static class WebHostBuilderWebListenerExtensions + { + /// + /// Specify WebListener as the server to be used by the web host. + /// + /// + /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure. + /// + /// + /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder. + /// + public static IWebHostBuilder UseWebListener(this IWebHostBuilder hostBuilder) + { + return hostBuilder.ConfigureServices(services => services.AddSingleton()); + } + + /// + /// Specify WebListener as the server to be used by the web host. + /// + /// + /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure. + /// + /// + /// A callback to configure WebListener options. + /// + /// + /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder. + /// + public static IWebHostBuilder UseWebListener(this IWebHostBuilder hostBuilder, Action options) + { + hostBuilder.ConfigureServices(services => + { + services.AddTransient, WebListenerOptionsSetup>(); + services.Configure(options); + }); + + return hostBuilder.UseWebListener(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs similarity index 72% rename from src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs rename to src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs index f7ca6cc178..814314e9a2 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/ServerAddressesFeature.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,13 +15,15 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. +using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Server.Features; +using System.Linq; +using System.Threading.Tasks; namespace Microsoft.AspNetCore.Server.WebListener { - internal class ServerAddressesFeature : IServerAddressesFeature + public class WebListenerOptions { - public ICollection Addresses { get; } = new List(); + public Microsoft.Net.Http.Server.WebListener Listener { get; set; } = new Microsoft.Net.Http.Server.WebListener(); } } diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index 6f57582cb9..7b574ffca5 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -24,6 +24,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Net.Http.Server; using Xunit; @@ -187,13 +189,11 @@ namespace Microsoft.AspNetCore.Server.WebListener var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app); dynamicServer.Dispose(); var rootUri = new Uri(root); - var factory = new ServerFactory(loggerFactory: null); - var server = factory.CreateServer(configuration: null); - var listener = server.Features.Get(); + var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); + server.Listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); } server.Start(new DummyApplication(app)); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs index 2c95f450bb..a439324a81 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs @@ -26,6 +26,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Net.Http.Server; using Xunit; @@ -253,11 +255,9 @@ namespace Microsoft.AspNetCore.Server.WebListener string address; using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } - var factory = new ServerFactory(loggerFactory: null); - var server = factory.CreateServer(configuration: null); - var listener = server.Features.Get(); - listener.UrlPrefixes.Add(UrlPrefix.Create(address)); - listener.SetRequestQueueLimit(1001); + var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); + server.Listener.UrlPrefixes.Add(UrlPrefix.Create(address)); + server.Listener.SetRequestQueueLimit(1001); using (server) { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs index 689a0ed98e..b78a3d8b15 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs @@ -17,8 +17,10 @@ using System; using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Server.Features; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Net.Http.Server; namespace Microsoft.AspNetCore.Server.WebListener @@ -53,7 +55,6 @@ namespace Microsoft.AspNetCore.Server.WebListener internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, out string root, out string baseAddress, RequestDelegate app) { - var factory = new ServerFactory(loggerFactory: null); lock (PortLock) { while (NextPort < MaxPort) @@ -64,10 +65,9 @@ namespace Microsoft.AspNetCore.Server.WebListener root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; baseAddress = prefix.ToString(); - var server = factory.CreateServer(configuration: null); - var listener = server.Features.Get(); - listener.UrlPrefixes.Add(prefix); - listener.AuthenticationManager.AuthenticationSchemes = authType; + var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); + server.Features.Get().Addresses.Add(baseAddress); + server.Listener.AuthenticationManager.AuthenticationSchemes = authType; try { server.Start(new DummyApplication(app)); @@ -89,8 +89,7 @@ namespace Microsoft.AspNetCore.Server.WebListener internal static IServer CreateServer(string scheme, string host, int port, string path, RequestDelegate app) { - var factory = new ServerFactory(loggerFactory: null); - var server = factory.CreateServer(configuration: null); + var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); server.Features.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); server.Start(new DummyApplication(app)); return server; From 6b0684cc4df5e6beb0a8cd98acaa00f3fda58d53 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 18 Apr 2016 13:04:05 -0700 Subject: [PATCH 340/597] Fix WebListenerOptionsSetup service registration --- samples/SelfHostServer/Startup.cs | 11 +++++++++++ .../WebHostBuilderWebListenerExtensions.cs | 6 ++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 0e276faca8..06e833b074 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -6,6 +6,8 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Server.WebListener; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; @@ -13,6 +15,15 @@ namespace SelfHostServer { public class Startup { + public void ConfigureServices(IServiceCollection services) + { + // Server options can be configured here instead of in Main. + services.Configure(options => + { + options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; + }); + } + public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { loggerfactory.AddConsole(LogLevel.Debug); diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs index f2cfe9deb2..0558a95703 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs @@ -40,7 +40,10 @@ namespace Microsoft.AspNetCore.Hosting /// public static IWebHostBuilder UseWebListener(this IWebHostBuilder hostBuilder) { - return hostBuilder.ConfigureServices(services => services.AddSingleton()); + return hostBuilder.ConfigureServices(services => { + services.AddTransient, WebListenerOptionsSetup>(); + services.AddSingleton(); + }); } /// @@ -59,7 +62,6 @@ namespace Microsoft.AspNetCore.Hosting { hostBuilder.ConfigureServices(services => { - services.AddTransient, WebListenerOptionsSetup>(); services.Configure(options); }); From 169a571a377ce150bab15cec6b8bbf43c9628949 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 18 Apr 2016 17:00:52 -0700 Subject: [PATCH 341/597] Bring Microsoft.NETCore.Platforms dependency back --- samples/HelloWorld/project.json | 1 + samples/HotAddSample/project.json | 1 + samples/SelfHostServer/project.json | 1 + .../project.json | 1 + test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 1 + 5 files changed, 5 insertions(+) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index ff0fe111a8..d367ee07c9 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,6 +3,7 @@ "emitEntryPoint": true }, "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.Net.Http.Server": "0.1.0-*", "Microsoft.Net.WebSockets.Server": "0.1.0-*" }, diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 36d50c8f32..053a21ca45 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,6 +1,7 @@ { "version": "1.0.0-*", "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 471564e28b..98ab1fe475 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,5 +1,6 @@ { "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 7592527454..f7a69e7696 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -1,6 +1,7 @@ { "testRunner": "xunit", "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit": "2.1.0" diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 159b5be103..9d84d2a05a 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,6 +1,7 @@ { "testRunner": "xunit", "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.Net.Http.Server": "0.1.0-*", "Microsoft.Net.WebSockets.Server": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", From 8c2756cffaa4fa5e706d1d98d6201703b230e724 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 19 Apr 2016 09:22:50 -0700 Subject: [PATCH 342/597] Fix service registration order. --- .../WebHostBuilderWebListenerExtensions.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs index 0558a95703..51c658b9f0 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs @@ -60,12 +60,10 @@ namespace Microsoft.AspNetCore.Hosting /// public static IWebHostBuilder UseWebListener(this IWebHostBuilder hostBuilder, Action options) { - hostBuilder.ConfigureServices(services => + return hostBuilder.UseWebListener().ConfigureServices(services => { services.Configure(options); }); - - return hostBuilder.UseWebListener(); } } } From 6829675f5f5ddc706f8a85aba01e1d83e29fcd57 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 19 Apr 2016 14:54:14 -0700 Subject: [PATCH 343/597] Use latest build of dotnet-test-xunit --- .../project.json | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index f7a69e7696..ad66c1182f 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -16,7 +16,7 @@ "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebHeaderCollection": "4.0.1-*", - "dotnet-test-xunit": "1.0.0-dev-*", + "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 9d84d2a05a..e5f4941810 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -18,7 +18,7 @@ "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebSockets.Client": "4.0.0-*", - "dotnet-test-xunit": "1.0.0-dev-*", + "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ From afd437f85f074a80695e90796663e5a91e879569 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Wed, 27 Apr 2016 18:43:11 -0700 Subject: [PATCH 344/597] Remove reference to UseDefaultHostConfiguration --- samples/HotAddSample/Startup.cs | 1 - samples/SelfHostServer/Startup.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index bfa147d918..d3b7753f80 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -92,7 +92,6 @@ namespace HotAddSample public static void Main(string[] args) { var host = new WebHostBuilder() - .UseDefaultHostingConfiguration(args) .UseStartup() .UseWebListener() .Build(); diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 06e833b074..3e3d72be83 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -49,7 +49,6 @@ namespace SelfHostServer public static void Main(string[] args) { var host = new WebHostBuilder() - .UseDefaultHostingConfiguration(args) .UseStartup() .UseWebListener(options => { From 5bcf3816048a02d42fd69ce5e0a627ce94301bf8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 2 May 2016 11:27:30 -0700 Subject: [PATCH 345/597] Fix build warnings --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNetCore.Server.WebListener/project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 2 +- src/Microsoft.Net.WebSockets.Server/project.json | 2 +- .../project.json | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index d367ee07c9..5355f1f1e4 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -1,5 +1,5 @@ { - "compilationOptions": { + "buildOptions": { "emitEntryPoint": true }, "dependencies": { diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 053a21ca45..fb1727b0ad 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -5,7 +5,7 @@ "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, - "compilationOptions": { + "buildOptions": { "emitEntryPoint": true }, "commands": { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 98ab1fe475..1fdc5efcb4 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -4,7 +4,7 @@ "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, - "compilationOptions": { + "buildOptions": { "emitEntryPoint": true }, "commands": { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 03d3aa25b8..3854697d13 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -6,7 +6,7 @@ "Microsoft.Net.Http.Headers": "1.0.0-*", "Microsoft.Net.Http.Server": "0.1.0-*" }, - "compilationOptions": { + "buildOptions": { "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index bfe06275c5..d2e7d1ed96 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -5,7 +5,7 @@ "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", "Microsoft.Extensions.Primitives": "1.0.0-*" }, - "compilationOptions": { + "buildOptions": { "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 99416df264..0a58d5ba4f 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -4,7 +4,7 @@ "dependencies": { "Microsoft.Net.Http.Server": "0.1.0-*" }, - "compilationOptions": { + "buildOptions": { "allowUnsafe": true, "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index ad66c1182f..1fc7773d62 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -1,6 +1,7 @@ { "testRunner": "xunit", "dependencies": { + "dotnet-test-xunit": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", @@ -16,7 +17,6 @@ "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebHeaderCollection": "4.0.1-*", - "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index e5f4941810..fb32fe6dc2 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,6 +1,7 @@ { "testRunner": "xunit", "dependencies": { + "dotnet-test-xunit": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.Net.Http.Server": "0.1.0-*", "Microsoft.Net.WebSockets.Server": "0.1.0-*", @@ -18,7 +19,6 @@ "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebSockets.Client": "4.0.0-*", - "dotnet-test-xunit": "1.0.0-*", "System.Diagnostics.Process": "4.1.0-*" }, "imports": [ From 3061a48a38d73afa40d1c776709ed6c26d537e6f Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 10 May 2016 10:59:42 -0700 Subject: [PATCH 346/597] Do not allow control characters in response headers. --- .../RequestProcessing/HeaderCollection.cs | 32 ++++++++++ .../ResponseHeaderTests.cs | 61 +++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs index 23778ddec5..2decf287e0 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs @@ -41,6 +41,8 @@ namespace Microsoft.Net.Http.Server } else { + ValidateHeaderCharacters(key); + ValidateHeaderCharacters(value); Store[key] = value; } } @@ -52,6 +54,8 @@ namespace Microsoft.Net.Http.Server set { ThrowIfReadOnly(); + ValidateHeaderCharacters(key); + ValidateHeaderCharacters(value); Store[key] = value; } } @@ -74,18 +78,24 @@ namespace Microsoft.Net.Http.Server public void Add(KeyValuePair item) { ThrowIfReadOnly(); + ValidateHeaderCharacters(item.Key); + ValidateHeaderCharacters(item.Value); Store.Add(item); } public void Add(string key, StringValues value) { ThrowIfReadOnly(); + ValidateHeaderCharacters(key); + ValidateHeaderCharacters(value); Store.Add(key, value); } public void Append(string key, string value) { ThrowIfReadOnly(); + ValidateHeaderCharacters(key); + ValidateHeaderCharacters(value); StringValues values; Store.TryGetValue(key, out values); Store[key] = StringValues.Concat(values, value); @@ -156,5 +166,27 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException("The response headers cannot be modified because the response has already started."); } } + + public static void ValidateHeaderCharacters(StringValues headerValues) + { + foreach (var value in headerValues) + { + ValidateHeaderCharacters(value); + } + } + + public static void ValidateHeaderCharacters(string headerCharacters) + { + if (headerCharacters != null) + { + foreach (var ch in headerCharacters) + { + if (ch < 0x20) + { + throw new InvalidOperationException(string.Format("Invalid control character in header: 0x{0:X2}", (byte)ch)); + } + } + } + } } } \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index 3a498ecbda..a788e2ffb4 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -1,11 +1,13 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; +using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.Net.Http.Server @@ -415,6 +417,65 @@ namespace Microsoft.Net.Http.Server } } + [Theory] + [InlineData("Server", "\r\nData")] + [InlineData("Server", "\0Data")] + [InlineData("Server", "Data\r")] + [InlineData("Server", "Da\0ta")] + [InlineData("Server", "Da\u001Fta")] + [InlineData("Unknown-Header", "\r\nData")] + [InlineData("Unknown-Header", "\0Data")] + [InlineData("Unknown-Header", "Data\0")] + [InlineData("Unknown-Header", "Da\nta")] + [InlineData("\r\nServer", "Data")] + [InlineData("Server\r", "Data")] + [InlineData("Ser\0ver", "Data")] + [InlineData("Server\r\n", "Data")] + [InlineData("\u001FServer", "Data")] + [InlineData("Unknown-Header\r\n", "Data")] + [InlineData("\0Unknown-Header", "Data")] + [InlineData("Unknown\r-Header", "Data")] + [InlineData("Unk\nown-Header", "Data")] + public async Task AddingControlCharactersToHeadersThrows(string key, string value) + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address); + + var context = await server.GetContextAsync(); + + var responseHeaders = context.Response.Headers; + + Assert.Throws(() => { + responseHeaders[key] = value; + }); + + Assert.Throws(() => { + responseHeaders[key] = new StringValues(new[] { "valid", value }); + }); + + Assert.Throws(() => { + ((IDictionary)responseHeaders)[key] = value; + }); + + Assert.Throws(() => { + var kvp = new KeyValuePair(key, value); + ((ICollection>)responseHeaders).Add(kvp); + }); + + Assert.Throws(() => { + var kvp = new KeyValuePair(key, value); + ((IDictionary)responseHeaders).Add(key, value); + }); + + context.Dispose(); + + HttpResponseMessage response = await responseTask; + response.EnsureSuccessStatusCode(); + } + } + private async Task SendRequestAsync(string uri, bool usehttp11 = true, bool sendKeepAlive = false) { using (HttpClient client = new HttpClient()) From aa7abe85216b73023c751e22e522539c2cee957d Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 17 May 2016 15:52:32 -0700 Subject: [PATCH 347/597] React to updated CoreCLR packages https://github.com/aspnet/Coherence/issues/97 --- src/Microsoft.Net.WebSockets.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 0a58d5ba4f..c7827defa3 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -22,7 +22,7 @@ "System.Net.WebSockets": "4.0.0-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", - "System.Security.Cryptography.Algorithms": "4.1.0-*", + "System.Security.Cryptography.Algorithms": "4.2.0-*", "System.Threading": "4.0.11-*", "System.Threading.Tasks": "4.0.11-*", "System.Threading.Timer": "4.0.1-*", From 072893cafe105238cf3db00d1e56f70d5fa956c6 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 18 May 2016 11:49:13 -0700 Subject: [PATCH 348/597] Revert "React to updated CoreCLR packages" This reverts commit aa7abe85216b73023c751e22e522539c2cee957d. --- src/Microsoft.Net.WebSockets.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index c7827defa3..0a58d5ba4f 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -22,7 +22,7 @@ "System.Net.WebSockets": "4.0.0-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", - "System.Security.Cryptography.Algorithms": "4.2.0-*", + "System.Security.Cryptography.Algorithms": "4.1.0-*", "System.Threading": "4.0.11-*", "System.Threading.Tasks": "4.0.11-*", "System.Threading.Timer": "4.0.1-*", From f5bd95b93f8c32c649f9c8075cfcd8626d2dc7d6 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 26 May 2016 18:22:38 -0700 Subject: [PATCH 349/597] React to updated CoreCLR packages https://github.com/aspnet/Coherence/issues/97 --- src/Microsoft.Net.WebSockets.Server/project.json | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index 0a58d5ba4f..c7827defa3 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -22,7 +22,7 @@ "System.Net.WebSockets": "4.0.0-*", "System.Resources.ResourceManager": "4.0.1-*", "System.Runtime.Extensions": "4.1.0-*", - "System.Security.Cryptography.Algorithms": "4.1.0-*", + "System.Security.Cryptography.Algorithms": "4.2.0-*", "System.Threading": "4.0.11-*", "System.Threading.Tasks": "4.0.11-*", "System.Threading.Timer": "4.0.1-*", diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index fb32fe6dc2..e427b85c5c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -15,7 +15,7 @@ "version": "1.0.0-*", "type": "platform" }, - "System.Net.Http": "4.0.1-*", + "System.Net.Http": "4.1.0-*", "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", "System.Net.WebSockets.Client": "4.0.0-*", From 55d2ef02b173a908a46343f2cd6742cb71f9ae0a Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Wed, 25 May 2016 17:07:02 -0700 Subject: [PATCH 350/597] Implement IHttpRequestFeature.RawTarget. --- .../FeatureContext.cs | 14 ++++++++++++++ .../RequestProcessing/Request.cs | 6 +++--- .../RequestTests.cs | 6 +++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index dd0408237b..ec906fdf37 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -62,6 +62,7 @@ namespace Microsoft.AspNetCore.Server.WebListener private string _query; private string _pathBase; private string _path; + private string _rawTarget; private IPAddress _remoteIpAddress; private IPAddress _localIpAddress; private int? _remotePort; @@ -207,6 +208,19 @@ namespace Microsoft.AspNetCore.Server.WebListener set { _query = value; } } + string IHttpRequestFeature.RawTarget + { + get + { + if (_rawTarget == null) + { + _rawTarget = Request.RawUrl; + } + return _rawTarget; + } + set { _rawTarget = value; } + } + string IHttpRequestFeature.Scheme { get diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 953556d88a..d2671ae7a2 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -296,15 +296,15 @@ namespace Microsoft.Net.Http.Server return _sslStatus != SslStatus.Insecure; } } - /* - internal string RawUrl + + public string RawUrl { get { return _rawUrl; } } - */ + public Version ProtocolVersion { get diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index 7b574ffca5..08d075089d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -51,6 +51,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal("/basepath", requestInfo.PathBase); Assert.Equal("/SomePath", requestInfo.Path); Assert.Equal("?SomeQuery", requestInfo.QueryString); + Assert.Equal("/basepath/SomePath?SomeQuery", requestInfo.RawTarget); Assert.Equal("HTTP/1.1", requestInfo.Protocol); // Server Keys @@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.WebListener [InlineData("/basepath/", "/basepath", "/basepath", "")] [InlineData("/basepath/", "/basepath/", "/basepath", "/")] [InlineData("/basepath/", "/basepath/subpath", "/basepath", "/subpath")] - [InlineData("/base path/", "/base%20path/sub path", "/base path", "/sub path")] + [InlineData("/base path/", "/base%20path/sub%20path", "/base path", "/sub path")] [InlineData("/base葉path/", "/base%E8%91%89path/sub%E8%91%89path", "/base葉path", "/sub葉path")] [InlineData("/basepath/", "/basepath/sub%2Fpath", "/basepath", "/sub%2Fpath")] public async Task Request_PathSplitting(string pathBase, string requestPath, string expectedPathBase, string expectedPath) @@ -106,6 +107,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(expectedPath, requestInfo.Path); Assert.Equal(expectedPathBase, requestInfo.PathBase); Assert.Equal(string.Empty, requestInfo.QueryString); + Assert.Equal(requestPath, requestInfo.RawTarget); // Trace identifier Assert.NotNull(requestIdentifierFeature); @@ -132,6 +134,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { var requestInfo = httpContext.Features.Get(); Assert.Equal("/%2F", requestInfo.Path); + Assert.Equal("/%252F", requestInfo.RawTarget); return Task.FromResult(0); })) { @@ -165,6 +168,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { Assert.Equal(expectedPath, requestInfo.Path); Assert.Equal(expectedPathBase, requestInfo.PathBase); + Assert.Equal(requestPath, requestInfo.RawTarget); // Trace identifier Assert.NotNull(requestIdentifierFeature); From 96d37a04e65c033dccf9889e38824c82790cc1c9 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 3 Jun 2016 17:12:43 -0700 Subject: [PATCH 351/597] React to Hosting TFM change --- src/Microsoft.AspNetCore.Server.WebListener/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 3854697d13..46b221b082 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -17,7 +17,7 @@ }, "frameworks": { "net451": {}, - "netstandard1.3": { + "netstandard1.5": { "dependencies": { "System.Security.Claims": "4.0.1-*" }, From 57b8e1cae8fa75feeecc67a0787e6b4741c54288 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 7 Jun 2016 06:39:57 -0700 Subject: [PATCH 352/597] Revert "React to Hosting TFM change" This reverts commit 96d37a04e65c033dccf9889e38824c82790cc1c9. --- src/Microsoft.AspNetCore.Server.WebListener/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 46b221b082..3854697d13 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -17,7 +17,7 @@ }, "frameworks": { "net451": {}, - "netstandard1.5": { + "netstandard1.3": { "dependencies": { "System.Security.Claims": "4.0.1-*" }, From eb726021dff4f7a51f251126f8b0cec255468297 Mon Sep 17 00:00:00 2001 From: jacalvar Date: Tue, 7 Jun 2016 22:53:31 -0700 Subject: [PATCH 353/597] Remove unncessary usings --- samples/HelloWorld/project.json | 5 +---- samples/HotAddSample/project.json | 5 +---- samples/SelfHostServer/project.json | 5 +---- src/Microsoft.AspNetCore.Server.WebListener/project.json | 5 +---- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 5355f1f1e4..a9a7895f6f 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -18,10 +18,7 @@ "version": "1.0.0-*", "type": "platform" } - }, - "imports": [ - "dnxcore50" - ] + } } } } \ No newline at end of file diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index fb1727b0ad..90c7734732 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -19,10 +19,7 @@ "version": "1.0.0-*", "type": "platform" } - }, - "imports": [ - "dnxcore50" - ] + } } } } \ No newline at end of file diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 1fdc5efcb4..ed7aa07c1c 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -18,10 +18,7 @@ "version": "1.0.0-*", "type": "platform" } - }, - "imports": [ - "dnxcore50" - ] + } } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 3854697d13..01d48055fc 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -20,10 +20,7 @@ "netstandard1.3": { "dependencies": { "System.Security.Claims": "4.0.1-*" - }, - "imports": [ - "portable-net451+win8" - ] + } } } } \ No newline at end of file From b441934f6576dfe7b0d55d146c78512b4a30b5aa Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 13 Jun 2016 15:29:07 -0700 Subject: [PATCH 354/597] Remove direct Microsoft.NETCore.Platforms dependency. - Microsoft.NETCore.App now pulls this package in. aspnet/Coherence-Signed#344 --- samples/HelloWorld/project.json | 1 - samples/HotAddSample/project.json | 1 - samples/SelfHostServer/project.json | 1 - .../project.json | 1 - test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 1 - 5 files changed, 5 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index a9a7895f6f..217b63187a 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,7 +3,6 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.Net.Http.Server": "0.1.0-*", "Microsoft.Net.WebSockets.Server": "0.1.0-*" }, diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 90c7734732..2ced8bd1c9 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,7 +1,6 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index ed7aa07c1c..5d77d489fb 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,6 +1,5 @@ { "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 1fc7773d62..89477b804a 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -2,7 +2,6 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit": "2.1.0" diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index e427b85c5c..191ff94190 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -2,7 +2,6 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.NETCore.Platforms": "1.0.1-*", "Microsoft.Net.Http.Server": "0.1.0-*", "Microsoft.Net.WebSockets.Server": "0.1.0-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", From 3e80775179fe59b6f6a8410beb0dcc6616d8c1d6 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 14 Jun 2016 16:22:41 -0700 Subject: [PATCH 355/597] Updating to release. --- NuGet.config | 2 +- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NuGet.config b/NuGet.config index 1707938c61..9db87a421e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..cf8bff13bb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..f88fe4052e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/release.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 10df99de671c7663bee6e55359a375475f0d1b09 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 16 Jun 2016 10:18:50 -0700 Subject: [PATCH 356/597] Updating to dev versions --- samples/HelloWorld/project.json | 4 ++-- samples/HotAddSample/project.json | 6 +++--- samples/SelfHostServer/project.json | 4 ++-- src/Microsoft.AspNetCore.Server.WebListener/project.json | 8 ++++---- src/Microsoft.Net.Http.Server/project.json | 6 +++--- src/Microsoft.Net.WebSockets.Server/project.json | 4 ++-- .../project.json | 4 ++-- .../project.json | 6 +++--- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 217b63187a..2cd8e62d8f 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,8 +3,8 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.Net.Http.Server": "0.1.0-*", - "Microsoft.Net.WebSockets.Server": "0.1.0-*" + "Microsoft.Net.Http.Server": "0.2.0-*", + "Microsoft.Net.WebSockets.Server": "0.2.0-*" }, "commands": { "sample": "HelloWorld" diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 2ced8bd1c9..d6538aa090 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,8 +1,8 @@ { - "version": "1.0.0-*", + "version": "1.1.0-*", "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" + "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", + "Microsoft.Extensions.Logging.Console": "1.1.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 5d77d489fb..f621b8021a 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,7 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" + "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", + "Microsoft.Extensions.Logging.Console": "1.1.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 01d48055fc..56cfd2f176 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -1,10 +1,10 @@ { - "version": "0.1.0-*", + "version": "0.2.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { - "Microsoft.AspNetCore.Hosting": "1.0.0-*", - "Microsoft.Net.Http.Headers": "1.0.0-*", - "Microsoft.Net.Http.Server": "0.1.0-*" + "Microsoft.AspNetCore.Hosting": "1.1.0-*", + "Microsoft.Net.Http.Headers": "1.1.0-*", + "Microsoft.Net.Http.Server": "0.2.0-*" }, "buildOptions": { "allowUnsafe": true, diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index d2e7d1ed96..ac4ff9de65 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,9 +1,9 @@ { - "version": "0.1.0-*", + "version": "0.2.0-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", - "Microsoft.Extensions.Primitives": "1.0.0-*" + "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", + "Microsoft.Extensions.Primitives": "1.1.0-*" }, "buildOptions": { "allowUnsafe": true, diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json index c7827defa3..dda1bf4231 100644 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ b/src/Microsoft.Net.WebSockets.Server/project.json @@ -1,8 +1,8 @@ { - "version": "0.1.0-*", + "version": "0.2.0-*", "description": "Implementation of WebSocket abstract base class. Used by WebListener.", "dependencies": { - "Microsoft.Net.Http.Server": "0.1.0-*" + "Microsoft.Net.Http.Server": "0.2.0-*" }, "buildOptions": { "allowUnsafe": true, diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 89477b804a..1c06616124 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -2,8 +2,8 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*", - "Microsoft.AspNetCore.Testing": "1.0.0-*", + "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", + "Microsoft.AspNetCore.Testing": "1.1.0-*", "xunit": "2.1.0" }, "frameworks": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 191ff94190..522b77234b 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -2,9 +2,9 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "1.0.0-*", - "Microsoft.Net.Http.Server": "0.1.0-*", - "Microsoft.Net.WebSockets.Server": "0.1.0-*", - "Microsoft.AspNetCore.Testing": "1.0.0-*", + "Microsoft.Net.Http.Server": "0.2.0-*", + "Microsoft.Net.WebSockets.Server": "0.2.0-*", + "Microsoft.AspNetCore.Testing": "1.1.0-*", "xunit": "2.1.0" }, "frameworks": { From f63e53b5976c6c0336249c52271e8393e2f1b295 Mon Sep 17 00:00:00 2001 From: moozzyk Date: Wed, 15 Jun 2016 10:46:24 -0700 Subject: [PATCH 357/597] Force 8-byte alignment on HTTP_REQUEST buffer Addresses #126 --- .../NativeInterop/UnsafeNativeMethods.cs | 43 ++++++++++--------- .../RequestProcessing/NativeRequestContext.cs | 41 ++++++++++++------ .../RequestProcessing/Request.cs | 19 +++++--- .../RequestProcessing/RequestHeaders.cs | 4 +- .../RequestProcessing/RequestStream.cs | 13 ++++-- src/Microsoft.Net.Http.Server/WebListener.cs | 2 +- 6 files changed, 77 insertions(+), 45 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index 8329a27cab..b4c732e1ee 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -1049,12 +1049,13 @@ namespace Microsoft.Net.Http.Server // Server API - internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob, IntPtr originalAddress) + internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob, + int requestOffset, IntPtr originalAddress) { // Return value. fixed (byte* pMemoryBlob = memoryBlob) { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); long fixup = pMemoryBlob - (byte*)originalAddress; int index; @@ -1064,7 +1065,7 @@ namespace Microsoft.Net.Http.Server HTTP_UNKNOWN_HEADER* pUnknownHeader = (HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders); for (index = 0; index < request->Headers.UnknownHeaderCount; index++) { - // For unknown headers, when header value is empty, RawValueLength will be 0 and + // For unknown headers, when header value is empty, RawValueLength will be 0 and // pRawValue will be null. if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) { @@ -1093,7 +1094,7 @@ namespace Microsoft.Net.Http.Server string header = null; HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; - // For known headers, when header value is empty, RawValueLength will be 0 and + // For known headers, when header value is empty, RawValueLength will be 0 and // pRawValue will point to empty string ("\0") if (pKnownHeader->pRawValue != null) { @@ -1103,11 +1104,12 @@ namespace Microsoft.Net.Http.Server return header; } - internal static string GetKnownHeader(byte[] memoryBlob, IntPtr originalAddress, int headerIndex) + internal static string GetKnownHeader(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, int headerIndex) { fixed (byte* pMemoryBlob = memoryBlob) { - return GetKnownHeader((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress, headerIndex); + return GetKnownHeader( + (HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress, headerIndex); } } @@ -1127,21 +1129,21 @@ namespace Microsoft.Net.Http.Server return verb; } - internal static unsafe string GetVerb(byte[] memoryBlob, IntPtr originalAddress) + internal static unsafe string GetVerb(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) { fixed (byte* pMemoryBlob = memoryBlob) { - return GetVerb((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress); + return GetVerb((HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress); } } - internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress) + internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) { // Return value. HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown; fixed (byte* pMemoryBlob = memoryBlob) { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) { verb = request->Verb; @@ -1151,13 +1153,14 @@ namespace Microsoft.Net.Http.Server return verb; } - internal static uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) + internal static uint GetChunks(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, + ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) { // Return value. uint dataRead = 0; fixed (byte* pMemoryBlob = memoryBlob) { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); long fixup = pMemoryBlob - (byte*)originalAddress; if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) @@ -1205,30 +1208,30 @@ namespace Microsoft.Net.Http.Server return dataRead; } - internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, IntPtr originalAddress) + internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) { fixed (byte* pMemoryBlob = memoryBlob) { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; - return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pRemoteAddress); + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); + return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pRemoteAddress); } } - internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, IntPtr originalAddress) + internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) { fixed (byte* pMemoryBlob = memoryBlob) { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; - return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pLocalAddress); + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); + return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pLocalAddress); } } - internal static SocketAddress GetEndPoint(byte[] memoryBlob, IntPtr originalAddress, byte* source) + internal static SocketAddress GetEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, byte* source) { fixed (byte* pMemoryBlob = memoryBlob) { IntPtr address = source != null ? - (IntPtr)(pMemoryBlob - (byte*)originalAddress + source) : IntPtr.Zero; + (IntPtr)(pMemoryBlob + requestOffset - (byte*)originalAddress + source) : IntPtr.Zero; return CopyOutAddress(address); } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 30ada89d29..cfc100f31f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -31,9 +31,11 @@ namespace Microsoft.Net.Http.Server internal unsafe class NativeRequestContext : IDisposable { private const int DefaultBufferSize = 4096; + private const int AlignmentPadding = 8; private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* _memoryBlob; private IntPtr _originalBlobAddress; private byte[] _backingBuffer; + private int _bufferAlignment; private SafeNativeOverlapped _nativeOverlapped; private AsyncAcceptContext _acceptResult; @@ -80,7 +82,15 @@ namespace Microsoft.Net.Http.Server { get { - return (uint)_backingBuffer.Length; + return (uint)_backingBuffer.Length - AlignmentPadding; + } + } + + internal int BufferAlignment + { + get + { + return _bufferAlignment; } } @@ -89,7 +99,7 @@ namespace Microsoft.Net.Http.Server get { UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* blob = _memoryBlob; - return (blob == null ? _originalBlobAddress : (IntPtr)blob); + return blob == null ? _originalBlobAddress : (IntPtr)blob; } } @@ -155,12 +165,13 @@ namespace Microsoft.Net.Http.Server private void SetBuffer(int size) { - _backingBuffer = size == 0 ? null : new byte[size]; + Debug.Assert(size != 0, "unexpected size"); + + _backingBuffer = new byte[size + AlignmentPadding]; } private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size) { - uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size; // We can't reuse overlapped objects if (_nativeOverlapped != null) { @@ -168,15 +179,19 @@ namespace Microsoft.Net.Http.Server _nativeOverlapped = null; nativeOverlapped.Dispose(); } - if (_nativeOverlapped == null) - { - SetBuffer(checked((int)newSize)); - var boundHandle = _acceptResult.Server.BoundHandle; - _nativeOverlapped = new SafeNativeOverlapped(boundHandle, - boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer)); - return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); - } - return RequestBlob; + + uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size; + SetBuffer(checked((int)newSize)); + var boundHandle = _acceptResult.Server.BoundHandle; + _nativeOverlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer)); + + // HttpReceiveHttpRequest expects the request pointer to be 8-byte-aligned or it fails. On ARM + // CLR creates buffers that are 4-byte-aligned so we need force 8-byte alignment. + var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); + _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07); + + return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment); } internal void Reset(ulong requestId, uint size) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index d2671ae7a2..72bc826284 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -141,7 +141,7 @@ namespace Microsoft.Net.Http.Server _httpVersion = new Version(major, minor); } - _httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, OriginalBlobAddress); + _httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, BufferAlignment, OriginalBlobAddress); _headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; @@ -190,6 +190,15 @@ namespace Microsoft.Net.Http.Server } } + internal int BufferAlignment + { + get + { + CheckDisposed(); + return _nativeRequestContext.BufferAlignment; + } + } + internal IntPtr OriginalBlobAddress { get @@ -304,7 +313,7 @@ namespace Microsoft.Net.Http.Server return _rawUrl; } } - + public Version ProtocolVersion { get @@ -329,7 +338,7 @@ namespace Microsoft.Net.Http.Server { if (_remoteEndPoint == null) { - _remoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, OriginalBlobAddress); + _remoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress); } return _remoteEndPoint; @@ -342,7 +351,7 @@ namespace Microsoft.Net.Http.Server { if (_localEndPoint == null) { - _localEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, OriginalBlobAddress); + _localEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress); } return _localEndPoint; @@ -406,7 +415,7 @@ namespace Microsoft.Net.Http.Server internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod() { - return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress); + return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, BufferAlignment, OriginalBlobAddress); } // Populates the client certificate. The result may be null if there is no client cert. diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs index d35e06cc56..1680f723d5 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs @@ -86,13 +86,13 @@ namespace Microsoft.Net.Http.Server private string GetKnownHeader(HttpSysRequestHeader header) { return UnsafeNclNativeMethods.HttpApi.GetKnownHeader(_requestMemoryBlob.RequestBuffer, - _requestMemoryBlob.OriginalBlobAddress, (int)header); + _requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress, (int)header); } private void GetUnknownHeaders(IDictionary extra) { UnsafeNclNativeMethods.HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer, - _requestMemoryBlob.OriginalBlobAddress); + _requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress); } void IDictionary.Add(string key, StringValues value) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 059dfe6822..bfbbf8cb1c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -147,7 +147,9 @@ namespace Microsoft.Net.Http.Server if (_dataChunkIndex != -1) { - dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, + _requestContext.Request.BufferAlignment, _requestContext.Request.OriginalBlobAddress, + ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); } if (_dataChunkIndex == -1 && dataRead < size) @@ -223,7 +225,9 @@ namespace Microsoft.Net.Http.Server uint dataRead = 0; if (_dataChunkIndex != -1) { - dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, + _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + if (_dataChunkIndex != -1 && dataRead == size) { asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, 0); @@ -339,7 +343,8 @@ namespace Microsoft.Net.Http.Server uint dataRead = 0; if (_dataChunkIndex != -1) { - dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, + _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); if (_dataChunkIndex != -1 && dataRead == size) { UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead); @@ -347,7 +352,7 @@ namespace Microsoft.Net.Http.Server return Task.FromResult((int)dataRead); } } - + if (_dataChunkIndex == -1 && dataRead < size) { uint statusCode = 0; diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 942cc18c8f..23f48fcdde 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -890,7 +890,7 @@ namespace Microsoft.Net.Http.Server blob = new byte[size]; fixed (byte* blobPtr = blob) { - // Http.sys team: ServiceName will always be null if + // Http.sys team: ServiceName will always be null if // HTTP_RECEIVE_SECURE_CHANNEL_TOKEN flag is set. statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( RequestQueueHandle, From e5dc948e479252e10cb94b145b8cb55d76eb7450 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Tue, 5 Jul 2016 21:05:37 -0700 Subject: [PATCH 358/597] Updating to RTM builds of xunit and Moq (#205) --- .../project.json | 19 +++++------------- .../project.json | 20 +++++-------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 1c06616124..e8ea925fcf 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -1,10 +1,10 @@ { "testRunner": "xunit", "dependencies": { - "dotnet-test-xunit": "1.0.0-*", + "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", "Microsoft.AspNetCore.Testing": "1.1.0-*", - "xunit": "2.1.0" + "xunit": "2.2.0-*" }, "frameworks": { "netcoreapp1.0": { @@ -15,22 +15,13 @@ }, "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", - "System.Net.WebHeaderCollection": "4.0.1-*", - "System.Diagnostics.Process": "4.1.0-*" - }, - "imports": [ - "dnxcore50", - "portable-net451+win8" - ] + "System.Net.WebHeaderCollection": "4.0.1-*" + } }, "net451": { "frameworkAssemblies": { "System.Net.Http": "", - "System.Net.Http.WebRequest": "", - "System.Threading.Tasks": "" - }, - "dependencies": { - "xunit.runner.console": "2.1.0" + "System.Net.Http.WebRequest": "" } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 522b77234b..d823390cbc 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,11 +1,11 @@ { "testRunner": "xunit", "dependencies": { - "dotnet-test-xunit": "1.0.0-*", + "dotnet-test-xunit": "2.2.0-*", "Microsoft.Net.Http.Server": "0.2.0-*", "Microsoft.Net.WebSockets.Server": "0.2.0-*", "Microsoft.AspNetCore.Testing": "1.1.0-*", - "xunit": "2.1.0" + "xunit": "2.2.0-*" }, "frameworks": { "netcoreapp1.0": { @@ -17,24 +17,14 @@ "System.Net.Http": "4.1.0-*", "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", - "System.Net.WebSockets.Client": "4.0.0-*", - "System.Diagnostics.Process": "4.1.0-*" - }, - "imports": [ - "dnxcore50", - "portable-net451+win8" - ] + "System.Net.WebSockets.Client": "4.0.0-*" + } }, "net451": { "frameworkAssemblies": { "System.DirectoryServices": "", "System.Net.Http": "", - "System.Net.Http.WebRequest": "", - "System.Runtime": "", - "System.Threading.Tasks": "" - }, - "dependencies": { - "xunit.runner.console": "2.1.0" + "System.Net.Http.WebRequest": "" } } } From 5541fc28bf6a7b6128c7f228a1e50d25e44c1a9e Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 7 Jul 2016 14:15:19 -0700 Subject: [PATCH 359/597] One build to rule them all - well, at least VS and command-line builds will share output - part of aspnet/Coherence-Signed#277 --- samples/HelloWorld/HelloWorld.xproj | 4 ++-- samples/HotAddSample/HotAddSample.xproj | 4 ++-- samples/SelfHostServer/SelfHostServer.xproj | 4 ++-- .../Microsoft.AspNetCore.Server.WebListener.xproj | 4 ++-- src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj | 4 ++-- .../Microsoft.Net.WebSockets.Server.xproj | 4 ++-- ...rosoft.AspNetCore.Server.WebListener.FunctionalTests.xproj | 4 ++-- .../Microsoft.Net.Http.Server.FunctionalTests.xproj | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/samples/HelloWorld/HelloWorld.xproj b/samples/HelloWorld/HelloWorld.xproj index 9172e56880..45065516db 100644 --- a/samples/HelloWorld/HelloWorld.xproj +++ b/samples/HelloWorld/HelloWorld.xproj @@ -7,8 +7,8 @@ 6daf3e6b-8e1b-4e6e-b9fe-7b1e5fdb7db4 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/samples/HotAddSample/HotAddSample.xproj b/samples/HotAddSample/HotAddSample.xproj index c65e2badf7..677fc90d52 100644 --- a/samples/HotAddSample/HotAddSample.xproj +++ b/samples/HotAddSample/HotAddSample.xproj @@ -7,8 +7,8 @@ 8bfa392a-8b67-4454-916b-67c545edfaef - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/samples/SelfHostServer/SelfHostServer.xproj b/samples/SelfHostServer/SelfHostServer.xproj index 31317b6e61..d2eaad70ff 100644 --- a/samples/SelfHostServer/SelfHostServer.xproj +++ b/samples/SelfHostServer/SelfHostServer.xproj @@ -7,8 +7,8 @@ 1236f93a-ac5c-4a77-9477-c88f040151ca - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj b/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj index 0ce3b5dc6d..aaf4cfb96b 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj +++ b/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj @@ -7,8 +7,8 @@ b9f45f9d-d206-47f0-8e5f-54ce2f0bdf92 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj index 24b618f386..57bd4cadb8 100644 --- a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj +++ b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj @@ -7,8 +7,8 @@ 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj b/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj index e2db8f32c7..a5fa974e8a 100644 --- a/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj +++ b/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj @@ -7,8 +7,8 @@ e788aeae-2cb4-4bfa-8746-d0bb7e93a1bb - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj index b172408b11..c510d82574 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj @@ -7,8 +7,8 @@ 4492ff4c-9032-411d-853f-46b01755e504 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj index db2158c7ca..3de44fa986 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj @@ -7,8 +7,8 @@ dcb6e0b1-223d-44e6-8696-4767e5b6e6a1 - ..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\artifacts\bin\ + .\obj + .\bin\ 2.0 From b132b69cb3b1e0de42a79338c03d7070140cabcf Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 13 Jul 2016 13:58:39 -0700 Subject: [PATCH 360/597] Log stack trace when logging exceptions #198 --- .../LogHelper.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs index a2ee73f12e..8ab5feee6e 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs @@ -51,32 +51,27 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - internal static void LogDebug(ILogger logger, string data) + internal static void LogDebug(ILogger logger, string location, Exception exception) { if (logger == null) { - Debug.WriteLine(data); + Console.WriteLine(location + Environment.NewLine + exception.ToString()); } else { - logger.LogDebug(data); + logger.LogDebug(0, exception, location); } } - internal static void LogDebug(ILogger logger, string location, Exception exception) - { - LogDebug(logger, location + "; " + exception.ToString()); - } - internal static void LogException(ILogger logger, string location, Exception exception) { if (logger == null) { - Debug.WriteLine(exception); + Debug.WriteLine(location + Environment.NewLine + exception.ToString()); } else { - logger.LogError(location, exception); + logger.LogError(0, exception, location); } } From 26ed532df582faa611d7e00f414660ac3ae586d3 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 14 Jul 2016 09:33:25 -0700 Subject: [PATCH 361/597] #210 Disable flaky caching tests. --- .../ResponseCachingTests.cs | 10 +++--- .../ResponseCachingTests.cs | 34 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index bcddd3be7a..541a1716e6 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_MaxAge_Cached() { var requestCount = 1; @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_SMaxAge_Cached() { var requestCount = 1; @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_SMaxAgeAndMaxAge_SMaxAgePreferredCached() { var requestCount = 1; @@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_Expires_Cached() { var requestCount = 1; @@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_MaxAgeAndExpires_MaxAgePreferred() { var requestCount = 1; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 5f739c7d91..6bfa2f0085 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -56,7 +56,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_SetTtlWithContentType_Cached() { string address; @@ -83,7 +83,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] // Http.Sys does not set the optional Age header for cached content. // http://tools.ietf.org/html/rfc7234#section-5.1 public async Task Caching_CheckAge_NotSentWithCachedContent() @@ -114,7 +114,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] // Http.Sys does not update the optional Age header for cached content. // http://tools.ietf.org/html/rfc7234#section-5.1 public async Task Caching_SetAge_AgeHeaderCachedAndNotUpdated() @@ -250,7 +250,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_SetTtlHuge_Cached() { string address; @@ -277,7 +277,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_SetTtlAndWriteBody_Cached() { string address; @@ -374,7 +374,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_WriteFullContentLength_Cached() { string address; @@ -436,7 +436,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_SendFileWithFullContentLength_Cached() { string address; @@ -465,7 +465,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_SetTtlAndStatusCode_Cached() { string address; @@ -562,7 +562,7 @@ namespace Microsoft.Net.Http.Server // RFC violation. http://tools.ietf.org/html/rfc7234#section-4.4 // "A cache MUST invalidate the effective Request URI ... when a non-error status code // is received in response to an unsafe request method." - [Theory] + [Theory(Skip = "https://github.com/aspnet/WebListener/issues/210")] // See HTTP_VERB for known verbs [InlineData("HEAD")] [InlineData("UNKNOWN")] @@ -629,7 +629,7 @@ namespace Microsoft.Net.Http.Server // RFC violation / implementation limiation, Vary is not respected. // http://tools.ietf.org/html/rfc7234#section-4.1 - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_SetVary_NotRespected() { string address; @@ -730,7 +730,7 @@ namespace Microsoft.Net.Http.Server // Responses can be cached for requests with Pragma: no-cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_RequestPragmaNoCache_Cached() { string address; @@ -759,7 +759,7 @@ namespace Microsoft.Net.Http.Server // RFC violation, Requests with Pragma: no-cache should not be served from cache. // http://tools.ietf.org/html/rfc7234#section-5.4 // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_RequestPragmaNoCache_NotRespectedAndServedFromCache() { string address; @@ -815,7 +815,7 @@ namespace Microsoft.Net.Http.Server // RFC violation, Requests with Cache-Control: no-cache should not be served from cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_RequestCacheControlNoCache_NotRespectedAndServedFromCache() { string address; @@ -843,7 +843,7 @@ namespace Microsoft.Net.Http.Server // RFC violation // http://tools.ietf.org/html/rfc7234#section-5.2.1.1 - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_RequestCacheControlMaxAgeZero_NotRespectedAndServedFromCache() { string address; @@ -871,7 +871,7 @@ namespace Microsoft.Net.Http.Server // RFC violation // http://tools.ietf.org/html/rfc7234#section-5.2.1.3 - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_RequestCacheControlMinFreshOutOfRange_NotRespectedAndServedFromCache() { string address; @@ -973,7 +973,7 @@ namespace Microsoft.Net.Http.Server } // http://tools.ietf.org/html/rfc7233#section-4.1 - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_RequestMultipleRangesFromCache_RangesServedFromCache() { string address; @@ -1034,7 +1034,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_RequestMultipleRangesFromCachedFile_ServedFromCache() { string address; From 07b078d4e37ffd20279865e38a86a815ab4cd429 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 13 Jul 2016 17:10:12 -0700 Subject: [PATCH 362/597] Remove support for specifying only ports in IServerAddresses #197 --- WebListener.sln | 18 +++- src/Microsoft.Net.Http.Server/UrlPrefix.cs | 53 ++++++------ .../Microsoft.Net.Http.Server.Tests.xproj | 20 +++++ .../UrlPrefixTests.cs | 85 +++++++++++++++++++ .../project.json | 19 +++++ 5 files changed, 167 insertions(+), 28 deletions(-) create mode 100644 test/Microsoft.Net.Http.Server.Tests/Microsoft.Net.Http.Server.Tests.xproj create mode 100644 test/Microsoft.Net.Http.Server.Tests/UrlPrefixTests.cs create mode 100644 test/Microsoft.Net.Http.Server.Tests/project.json diff --git a/WebListener.sln b/WebListener.sln index 5570995d52..52409addaa 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject @@ -32,6 +31,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HotAddSample", "samples\HotAddSample\HotAddSample.xproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server.Tests", "test\Microsoft.Net.Http.Server.Tests\Microsoft.Net.Http.Server.Tests.xproj", "{E837249E-E666-4DF2-AFC3-7A4D70234F9F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -134,6 +135,18 @@ Global {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|x86.ActiveCfg = Release|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Release|x86.Build.0 = Release|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Debug|x86.ActiveCfg = Debug|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Debug|x86.Build.0 = Debug|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Release|Any CPU.Build.0 = Release|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Release|x86.ActiveCfg = Release|Any CPU + {E837249E-E666-4DF2-AFC3-7A4D70234F9F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -148,5 +161,6 @@ Global {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1} = {E183C826-1360-4DFF-9994-F33CED5C8525} {8BFA392A-8B67-4454-916B-67C545EDFAEF} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} + {E837249E-E666-4DF2-AFC3-7A4D70234F9F} = {E183C826-1360-4DFF-9994-F33CED5C8525} EndGlobalSection EndGlobal diff --git a/src/Microsoft.Net.Http.Server/UrlPrefix.cs b/src/Microsoft.Net.Http.Server/UrlPrefix.cs index 8e72903252..fb4e8c070b 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefix.cs @@ -117,49 +117,50 @@ namespace Microsoft.Net.Http.Server string host = null; int? port = null; string path = null; - string whole = prefix ?? string.Empty; + var whole = prefix ?? string.Empty; - int delimiterStart1 = whole.IndexOf("://", StringComparison.Ordinal); - if (delimiterStart1 < 0) + var schemeDelimiterEnd = whole.IndexOf("://", StringComparison.Ordinal); + if (schemeDelimiterEnd < 0) { - int aPort; - if (int.TryParse(whole, NumberStyles.None, CultureInfo.InvariantCulture, out aPort)) - { - return UrlPrefix.Create("http", "localhost", aPort, "/"); - } - throw new FormatException("Invalid prefix, missing scheme separator: " + prefix); } - int delimiterEnd1 = delimiterStart1 + "://".Length; + var hostDelimiterStart = schemeDelimiterEnd + "://".Length; - int delimiterStart3 = whole.IndexOf("/", delimiterEnd1, StringComparison.Ordinal); - if (delimiterStart3 < 0) + var pathDelimiterStart = whole.IndexOf("/", hostDelimiterStart, StringComparison.Ordinal); + if (pathDelimiterStart < 0) { - delimiterStart3 = whole.Length; + pathDelimiterStart = whole.Length; } - int delimiterStart2 = whole.LastIndexOf(":", delimiterStart3 - 1, delimiterStart3 - delimiterEnd1, StringComparison.Ordinal); - int delimiterEnd2 = delimiterStart2 + ":".Length; - if (delimiterStart2 < 0) + var hostDelimiterEnd = whole.LastIndexOf(":", pathDelimiterStart - 1, pathDelimiterStart - hostDelimiterStart, StringComparison.Ordinal); + if (hostDelimiterEnd < 0) { - delimiterStart2 = delimiterStart3; - delimiterEnd2 = delimiterStart3; + hostDelimiterEnd = pathDelimiterStart; } - scheme = whole.Substring(0, delimiterStart1); - string portString = whole.Substring(delimiterEnd2, delimiterStart3 - delimiterEnd2); + scheme = whole.Substring(0, schemeDelimiterEnd); + var portString = whole.Substring(hostDelimiterEnd, pathDelimiterStart - hostDelimiterEnd); // The leading ":" is included int portValue; - if (int.TryParse(portString, NumberStyles.Integer, CultureInfo.InvariantCulture, out portValue)) + if (!string.IsNullOrEmpty(portString)) { - host = whole.Substring(delimiterEnd1, delimiterStart2 - delimiterEnd1); - port = portValue; + var portValueString = portString.Substring(1); // Trim the leading ":" + if (int.TryParse(portValueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out portValue)) + { + host = whole.Substring(hostDelimiterStart, hostDelimiterEnd - hostDelimiterStart); + port = portValue; + } + else + { + // This means a port was specified but was invalid or empty. + throw new FormatException("Invalid prefix, invalid port speficification: " + prefix); + } } else { - host = whole.Substring(delimiterEnd1, delimiterStart3 - delimiterEnd1); + host = whole.Substring(hostDelimiterStart, pathDelimiterStart - hostDelimiterStart); } - path = whole.Substring(delimiterStart3); + path = whole.Substring(pathDelimiterStart); - return UrlPrefix.Create(scheme, host, port, path); + return Create(scheme, host, port, path); } public bool IsHttps { get; private set; } diff --git a/test/Microsoft.Net.Http.Server.Tests/Microsoft.Net.Http.Server.Tests.xproj b/test/Microsoft.Net.Http.Server.Tests/Microsoft.Net.Http.Server.Tests.xproj new file mode 100644 index 0000000000..ed2140ef02 --- /dev/null +++ b/test/Microsoft.Net.Http.Server.Tests/Microsoft.Net.Http.Server.Tests.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + e837249e-e666-4df2-afc3-7a4d70234f9f + .\obj + .\bin\ + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.Tests/UrlPrefixTests.cs b/test/Microsoft.Net.Http.Server.Tests/UrlPrefixTests.cs new file mode 100644 index 0000000000..fece76e422 --- /dev/null +++ b/test/Microsoft.Net.Http.Server.Tests/UrlPrefixTests.cs @@ -0,0 +1,85 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Text; +using Xunit; + +namespace Microsoft.Net.Http.Server +{ + public class UrlPrefixTests + { + [Theory] + [InlineData("")] + [InlineData("5000")] + [InlineData("//noscheme")] + public void CreateThrowsForUrlsWithoutSchemeDelimiter(string url) + { + Assert.Throws(() => UrlPrefix.Create(url)); + } + + [Theory] + [InlineData("://emptyscheme")] + [InlineData("://")] + [InlineData("://:5000")] + public void CreateThrowsForUrlsWithEmptyScheme(string url) + { + Assert.Throws(() => UrlPrefix.Create(url)); + } + + [Theory] + [InlineData("http://")] + [InlineData("http://:5000")] + [InlineData("http:///")] + [InlineData("http:///:5000")] + [InlineData("http:////")] + [InlineData("http:////:5000")] + public void CreateThrowsForUrlsWithoutHost(string url) + { + Assert.Throws(() => UrlPrefix.Create(url)); + } + + [Theory] + [InlineData("http://www.example.com:NOTAPORT")] + [InlineData("https://www.example.com:NOTAPORT")] + [InlineData("http://www.example.com:NOTAPORT/")] + [InlineData("http://foo:/tmp/weblistener-test.sock:5000/doesn't/matter")] + public void CreateThrowsForUrlsWithInvalidPorts(string url) + { + Assert.Throws(() => UrlPrefix.Create(url)); + } + + [Theory] + [InlineData("http://+", "http", "+", "80", "/", "http://+:80/")] + [InlineData("http://*", "http", "*", "80", "/", "http://*:80/")] + [InlineData("http://localhost", "http", "localhost", "80", "/", "http://localhost:80/")] + [InlineData("http://www.example.com", "http", "www.example.com", "80", "/", "http://www.example.com:80/")] + [InlineData("https://www.example.com", "https", "www.example.com", "443", "/", "https://www.example.com:443/")] + [InlineData("http://www.example.com/", "http", "www.example.com", "80", "/", "http://www.example.com:80/")] + [InlineData("http://www.example.com/foo?bar=baz", "http", "www.example.com", "80", "/foo?bar=baz/", "http://www.example.com:80/foo?bar=baz/")] + [InlineData("http://www.example.com:5000", "http", "www.example.com", "5000", "/", "http://www.example.com:5000/")] + [InlineData("https://www.example.com:5000", "https", "www.example.com", "5000", "/", "https://www.example.com:5000/")] + [InlineData("http://www.example.com:5000/", "http", "www.example.com", "5000", "/", "http://www.example.com:5000/")] + [InlineData("http://www.example.com/foo:bar", "http", "www.example.com", "80", "/foo:bar/", "http://www.example.com:80/foo:bar/")] + public void UrlsAreParsedCorrectly(string url, string scheme, string host, string port, string pathBase, string toString) + { + var urlPrefix = UrlPrefix.Create(url); + + Assert.Equal(scheme, urlPrefix.Scheme); + Assert.Equal(host, urlPrefix.Host); + Assert.Equal(port, urlPrefix.Port); + Assert.Equal(pathBase, urlPrefix.Path); + + Assert.Equal(toString ?? url, urlPrefix.ToString()); + } + + [Fact] + public void PathBaseIsNotNormalized() + { + var urlPrefix = UrlPrefix.Create("http://localhost:8080/p\u0041\u030Athbase"); + + Assert.False(urlPrefix.Path.IsNormalized(NormalizationForm.FormC)); + Assert.Equal("/p\u0041\u030Athbase/", urlPrefix.Path); + } + } +} diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json new file mode 100644 index 0000000000..f4d93ce1af --- /dev/null +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -0,0 +1,19 @@ +{ + "testRunner": "xunit", + "dependencies": { + "dotnet-test-xunit": "2.2.0-*", + "Microsoft.Net.Http.Server": "0.2.0-*", + "xunit": "2.2.0-*" + }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-*", + "type": "platform" + } + } + }, + "net451": { } + } +} \ No newline at end of file From 3d2e1c4d3e21c3b70478392b0370ba998895c54f Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 15 Jul 2016 16:34:20 -0700 Subject: [PATCH 363/597] Factoring out UrlGroup, ServerSession, RequestQueue, ChannelBinding, Disconnect Listener. --- .../AsyncAcceptContext.cs | 2 +- .../AuthenticationManager.cs | 2 +- .../NativeInterop/DisconnectListener.cs | 165 +++++ .../NativeInterop/RequestQueue.cs | 119 ++++ .../NativeInterop/ServerSession.cs | 48 ++ .../NativeInterop/UnsafeNativeMethods.cs | 10 +- .../NativeInterop/UrlGroup.cs | 119 ++++ .../RequestProcessing/ClientCertLoader.cs | 88 ++- .../RequestProcessing/NativeRequestContext.cs | 2 +- .../RequestProcessing/RequestContext.cs | 26 +- .../RequestStreamAsyncResult.cs | 2 +- .../ResponseStreamAsyncResult.cs | 4 +- .../TimeoutManager.cs | 2 +- src/Microsoft.Net.Http.Server/UrlPrefix.cs | 2 +- .../UrlPrefixCollection.cs | 50 +- src/Microsoft.Net.Http.Server/WebListener.cs | 604 +++--------------- .../ResponseCachingTests.cs | 2 +- 17 files changed, 644 insertions(+), 603 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs create mode 100644 src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs create mode 100644 src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs create mode 100644 src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs diff --git a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs index a03a65a047..ba34877b2a 100644 --- a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs @@ -165,7 +165,7 @@ namespace Microsoft.Net.Http.Server retry = false; uint bytesTransferred = 0; statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest( - Server.RequestQueueHandle, + Server.RequestQueue.Handle, _nativeRequestContext.RequestBlob->RequestId, (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, _nativeRequestContext.RequestBlob, diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 6a8d4f66c4..877e8077ed 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -100,7 +100,7 @@ namespace Microsoft.Net.Http.Server IntPtr infoptr = new IntPtr(&authInfo); - _server.SetUrlGroupProperty( + _server.UrlGroup.SetProperty( UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, infoptr, (uint)AuthInfoSize); } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs b/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs new file mode 100644 index 0000000000..478a343177 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Collections.Concurrent; +using System.ComponentModel; +using System.Threading; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Net.Http.Server +{ + internal class DisconnectListener + { + private readonly ConcurrentDictionary _connectionCancellationTokens + = new ConcurrentDictionary(); + + private readonly RequestQueue _requestQueue; + private readonly ILogger _logger; + + internal DisconnectListener(RequestQueue requestQueue, ILogger logger) + { + _requestQueue = requestQueue; + _logger = logger; + } + + internal CancellationToken GetTokenForConnection(ulong connectionId) + { + try + { + // Create exactly one CancellationToken per connection. + return GetOrCreateDisconnectToken(connectionId); + } + catch (Win32Exception exception) + { + LogHelper.LogException(_logger, "GetConnectionToken", exception); + return CancellationToken.None; + } + } + + private CancellationToken GetOrCreateDisconnectToken(ulong connectionId) + { + // Read case is performance sensitive + ConnectionCancellation cancellation; + if (!_connectionCancellationTokens.TryGetValue(connectionId, out cancellation)) + { + cancellation = GetCreatedConnectionCancellation(connectionId); + } + return cancellation.GetCancellationToken(connectionId); + } + + private ConnectionCancellation GetCreatedConnectionCancellation(ulong connectionId) + { + // Race condition on creation has no side effects + var cancellation = new ConnectionCancellation(this); + return _connectionCancellationTokens.GetOrAdd(connectionId, cancellation); + } + + private unsafe CancellationToken CreateDisconnectToken(ulong connectionId) + { + LogHelper.LogDebug(_logger, "CreateDisconnectToken", "Registering connection for disconnect for connection ID: " + connectionId); + + // Create a nativeOverlapped callback so we can register for disconnect callback + var cts = new CancellationTokenSource(); + + SafeNativeOverlapped nativeOverlapped = null; + var boundHandle = _requestQueue.BoundHandle; + nativeOverlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped( + (errorCode, numBytes, overlappedPtr) => + { + LogHelper.LogDebug(_logger, "CreateDisconnectToken", "http.sys disconnect callback fired for connection ID: " + connectionId); + + // Free the overlapped + nativeOverlapped.Dispose(); + + // Pull the token out of the list and Cancel it. + ConnectionCancellation token; + _connectionCancellationTokens.TryRemove(connectionId, out token); + try + { + cts.Cancel(); + } + catch (AggregateException exception) + { + LogHelper.LogException(_logger, "CreateDisconnectToken Callback", exception); + } + + cts.Dispose(); + }, + null, null)); + + uint statusCode; + try + { + statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnectEx(requestQueueHandle: _requestQueue.Handle, + connectionId: connectionId, reserved: 0, overlapped: nativeOverlapped); + } + catch (Win32Exception exception) + { + statusCode = (uint)exception.NativeErrorCode; + LogHelper.LogException(_logger, "CreateDisconnectToken", exception); + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING && + statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + // We got an unknown result so return a None + // TODO: return a canceled token? + return CancellationToken.None; + } + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + // TODO: return a canceled token? + return CancellationToken.None; + } + + return cts.Token; + } + + private class ConnectionCancellation + { + private readonly DisconnectListener _parent; + private volatile bool _initialized; // Must be volatile because initialization is synchronized + private CancellationToken _cancellationToken; + + public ConnectionCancellation(DisconnectListener parent) + { + _parent = parent; + } + + internal CancellationToken GetCancellationToken(ulong connectionId) + { + // Initialized case is performance sensitive + if (_initialized) + { + return _cancellationToken; + } + return InitializeCancellationToken(connectionId); + } + + private CancellationToken InitializeCancellationToken(ulong connectionId) + { + object syncObject = this; +#pragma warning disable 420 // Disable warning about volatile by reference since EnsureInitialized does volatile operations + return LazyInitializer.EnsureInitialized(ref _cancellationToken, ref _initialized, ref syncObject, () => _parent.CreateDisconnectToken(connectionId)); +#pragma warning restore 420 + } + } + } +} diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs b/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs new file mode 100644 index 0000000000..6b3ef07665 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Net.Http.Server +{ + internal class RequestQueue + { + private static readonly int BindingInfoSize = + Marshal.SizeOf(); + + private readonly UrlGroup _urlGroup; + private readonly ILogger _logger; + + internal RequestQueue(UrlGroup urlGroup, ILogger logger) + { + _urlGroup = urlGroup; + _logger = logger; + + HttpRequestQueueV2Handle requestQueueHandle = null; + var statusCode = UnsafeNclNativeMethods.SafeNetHandles.HttpCreateRequestQueue( + UnsafeNclNativeMethods.HttpApi.Version, null, null, 0, out requestQueueHandle); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new WebListenerException((int)statusCode); + } + + // Disabling callbacks when IO operation completes synchronously (returns ErrorCodes.ERROR_SUCCESS) + if (WebListener.SkipIOCPCallbackOnSuccess && + !UnsafeNclNativeMethods.SetFileCompletionNotificationModes( + requestQueueHandle, + UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipCompletionPortOnSuccess | + UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipSetEventOnHandle)) + { + throw new WebListenerException(Marshal.GetLastWin32Error()); + } + + Handle = requestQueueHandle; + BoundHandle = ThreadPoolBoundHandle.BindHandle(Handle); + } + + internal SafeHandle Handle { get; } + internal ThreadPoolBoundHandle BoundHandle { get; } + + internal unsafe void AttachToUrlGroup() + { + // Set the association between request queue and url group. After this, requests for registered urls will + // get delivered to this request queue. + + var info = new UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO(); + info.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + info.RequestQueueHandle = Handle.DangerousGetHandle(); + + var infoptr = new IntPtr(&info); + + _urlGroup.SetProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + infoptr, (uint)BindingInfoSize); + } + + internal unsafe void DetachFromUrlGroup() + { + // Break the association between request queue and url group. After this, requests for registered urls + // will get 503s. + // Note that this method may be called multiple times (Stop() and then Abort()). This + // is fine since http.sys allows to set HttpServerBindingProperty multiple times for valid + // Url groups. + + var info = new UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO(); + info.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + info.RequestQueueHandle = IntPtr.Zero; + + var infoptr = new IntPtr(&info); + + _urlGroup.SetProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + infoptr, (uint)BindingInfoSize, throwOnError: false); + } + + // The listener must be active for this to work. + internal unsafe void SetLengthLimit(long length) + { + var result = UnsafeNclNativeMethods.HttpApi.HttpSetRequestQueueProperty(Handle, + UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, + new IntPtr((void*)&length), (uint)Marshal.SizeOf(), 0, IntPtr.Zero); + + if (result != 0) + { + throw new WebListenerException((int)result); + } + } + + public void Dispose() + { + BoundHandle.Dispose(); + Handle.Dispose(); + } + } +} diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs new file mode 100644 index 0000000000..1640efb500 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Diagnostics; + +namespace Microsoft.Net.Http.Server +{ + internal class ServerSession : IDisposable + { + internal unsafe ServerSession() + { + ulong serverSessionId = 0; + var statusCode = UnsafeNclNativeMethods.HttpApi.HttpCreateServerSession( + UnsafeNclNativeMethods.HttpApi.Version, &serverSessionId, 0); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new WebListenerException((int)statusCode); + } + + Debug.Assert(serverSessionId != 0, "Invalid id returned by HttpCreateServerSession"); + + Id = new HttpServerSessionHandle(serverSessionId); + } + + public HttpServerSessionHandle Id { get; private set; } + + public void Dispose() + { + Id.Dispose(); + } + } +} diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index b4c732e1ee..b5a4162058 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -1025,15 +1025,7 @@ namespace Microsoft.Net.Http.Server version.HttpApiMajorVersion = majorVersion; version.HttpApiMinorVersion = minorVersion; - // For pre-Win7 OS versions, we need to check whether http.sys contains the CBT patch. - // We do so by passing HTTP_INITIALIZE_CBT flag to HttpInitialize. If the flag is not - // supported, http.sys is not patched. Note that http.sys will return invalid parameter - // also on Win7, even though it shipped with CBT support. Therefore we must not pass - // the flag on Win7 and later. - uint statusCode = ErrorCodes.ERROR_SUCCESS; - - // on Win7 and later, we don't pass the CBT flag. CBT is always supported. - statusCode = HttpApi.HttpInitialize(version, (uint)HTTP_FLAGS.HTTP_INITIALIZE_SERVER, null); + var statusCode = HttpApi.HttpInitialize(version, (uint)HTTP_FLAGS.HTTP_INITIALIZE_SERVER, null); supported = statusCode == ErrorCodes.ERROR_SUCCESS; } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs new file mode 100644 index 0000000000..cb4af099df --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Diagnostics; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Net.Http.Server +{ + internal class UrlGroup : IDisposable + { + private ServerSession _serverSession; + private ILogger _logger; + private bool _disposed; + + internal unsafe UrlGroup(ServerSession serverSession, ILogger logger) + { + _serverSession = serverSession; + _logger = logger; + + ulong urlGroupId = 0; + var statusCode = UnsafeNclNativeMethods.HttpApi.HttpCreateUrlGroup( + _serverSession.Id.DangerousGetServerSessionId(), &urlGroupId, 0); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new WebListenerException((int)statusCode); + } + + Debug.Assert(urlGroupId != 0, "Invalid id returned by HttpCreateUrlGroup"); + Id = urlGroupId; + } + + internal ulong Id { get; private set; } + + internal void SetProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) + { + Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); + + var statusCode = UnsafeNclNativeMethods.HttpApi.HttpSetUrlGroupProperty(Id, property, info, infosize); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + var exception = new WebListenerException((int)statusCode); + LogHelper.LogException(_logger, "SetUrlGroupProperty", exception); + if (throwOnError) + { + throw exception; + } + } + } + + internal void RegisterPrefix(string uriPrefix, int contextId) + { + LogHelper.LogInfo(_logger, "Listening on prefix: " + uriPrefix); + + var statusCode = UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup(Id, uriPrefix, (ulong)contextId, 0); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS) + { + throw new WebListenerException((int)statusCode, string.Format(Resources.Exception_PrefixAlreadyRegistered, uriPrefix)); + } + else + { + throw new WebListenerException((int)statusCode); + } + } + } + + internal bool UnregisterPrefix(string uriPrefix) + { + LogHelper.LogInfo(_logger, "Stop listening on prefix: " + uriPrefix); + + var statusCode = UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup(Id, uriPrefix, 0); + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) + { + return false; + } + return true; + } + + public void Dispose() + { + if (_disposed) + { + return; + } + + _disposed = true; + + Debug.Assert(Id != 0, "HttpCloseUrlGroup called with invalid url group id"); + + uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpCloseUrlGroup(Id); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + LogHelper.LogError(_logger, "CleanupV2Config", "Result: " + statusCode); + } + Id = 0; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs index 8ae8305a87..62197abf1f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs @@ -22,14 +22,17 @@ // ----------------------------------------------------------------------- using System; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Security; +using System.Security.Authentication.ExtendedProtection; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { @@ -39,7 +42,9 @@ namespace Microsoft.Net.Http.Server { private const uint CertBoblSize = 1500; private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(WaitCallback); - + private static readonly int RequestChannelBindStatusSize = + Marshal.SizeOf(); + private SafeNativeOverlapped _overlapped; private byte[] _backingBuffer; private UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* _memoryBlob; @@ -144,7 +149,7 @@ namespace Microsoft.Net.Http.Server return; } _backingBuffer = new byte[checked((int)size)]; - var boundHandle = RequestContext.Server.BoundHandle; + var boundHandle = RequestContext.Server.RequestQueue.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer)); _memoryBlob = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); @@ -362,5 +367,84 @@ namespace Microsoft.Net.Http.Server { get { return _tcs.Task.IsCompleted; } } + + internal static unsafe ChannelBinding GetChannelBindingFromTls(RequestQueue requestQueue, ulong connectionId, ILogger logger) + { + // +128 since a CBT is usually <128 thus we need to call HRCC just once. If the CBT + // is >128 we will get ERROR_MORE_DATA and call again + int size = RequestChannelBindStatusSize + 128; + + Debug.Assert(size >= 0); + + byte[] blob = null; + SafeLocalFreeChannelBinding token = null; + + uint bytesReceived = 0; ; + uint statusCode; + + do + { + blob = new byte[size]; + fixed (byte* blobPtr = blob) + { + // Http.sys team: ServiceName will always be null if + // HTTP_RECEIVE_SECURE_CHANNEL_TOKEN flag is set. + statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( + requestQueue.Handle, + connectionId, + (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN, + blobPtr, + (uint)size, + &bytesReceived, + SafeNativeOverlapped.Zero); + + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + int tokenOffset = GetTokenOffsetFromBlob((IntPtr)blobPtr); + int tokenSize = GetTokenSizeFromBlob((IntPtr)blobPtr); + Debug.Assert(tokenSize < Int32.MaxValue); + + token = SafeLocalFreeChannelBinding.LocalAlloc(tokenSize); + + Marshal.Copy(blob, tokenOffset, token.DangerousGetHandle(), tokenSize); + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) + { + int tokenSize = GetTokenSizeFromBlob((IntPtr)blobPtr); + Debug.Assert(tokenSize < Int32.MaxValue); + + size = RequestChannelBindStatusSize + tokenSize; + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER) + { + LogHelper.LogError(logger, "GetChannelBindingFromTls", "Channel binding is not supported."); + return null; // old schannel library which doesn't support CBT + } + else + { + // It's up to the consumer to fail if the missing ChannelBinding matters to them. + LogHelper.LogException(logger, "GetChannelBindingFromTls", new WebListenerException((int)statusCode)); + break; + } + } + } + while (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); + + return token; + } + + private static int GetTokenOffsetFromBlob(IntPtr blob) + { + Debug.Assert(blob != IntPtr.Zero); + IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); + Debug.Assert(tokenPointer != IntPtr.Zero); + return (int)IntPtrHelper.Subtract(tokenPointer, blob); + } + + private static int GetTokenSizeFromBlob(IntPtr blob) + { + Debug.Assert(blob != IntPtr.Zero); + return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); + } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index cfc100f31f..49355872f6 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -182,7 +182,7 @@ namespace Microsoft.Net.Http.Server uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size; SetBuffer(checked((int)newSize)); - var boundHandle = _acceptResult.Server.BoundHandle; + var boundHandle = _acceptResult.Server.RequestQueue.BoundHandle; _nativeOverlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer)); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 3fe3b9a9c8..c0fede1e33 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -22,9 +22,11 @@ //------------------------------------------------------------------------------ using System; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.InteropServices; +using System.Security.Authentication.ExtendedProtection; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; @@ -84,7 +86,7 @@ namespace Microsoft.Net.Http.Server // We need to be able to dispose of the registrations each request to prevent leaks. if (!_disconnectToken.HasValue) { - var connectionDisconnectToken = _server.RegisterForDisconnectNotification(this); + var connectionDisconnectToken = _server.DisconnectListener.GetTokenForConnection(Request.ConnectionId); if (connectionDisconnectToken.CanBeCanceled) { @@ -117,7 +119,7 @@ namespace Microsoft.Net.Http.Server { get { - return _server.RequestQueueHandle; + return _server.RequestQueue.Handle; } } @@ -167,17 +169,25 @@ namespace Microsoft.Net.Http.Server Response.SendOpaqueUpgrade(); // TODO: Async Request.SwitchToOpaqueMode(); Response.SwitchToOpaqueMode(); - Stream opaqueStream = new OpaqueStream(Request.Body, Response.Body); - return Task.FromResult(opaqueStream); + var opaqueStream = new OpaqueStream(Request.Body, Response.Body); + return Task.FromResult(opaqueStream); } - /* - public bool TryGetChannelBinding(ref ChannelBinding value) + // TODO: Public when needed + internal bool TryGetChannelBinding(ref ChannelBinding value) { - value = Server.GetChannelBinding(Request.ConnectionId, Request.IsSecureConnection); + if (!Request.IsSecureConnection) + { + LogHelper.LogDebug(Logger, "TryGetChannelBinding", "Channel binding requires HTTPS."); + return false; + } + + value = ClientCertLoader.GetChannelBindingFromTls(Server.RequestQueue, Request.ConnectionId, Logger); + + Debug.Assert(value != null, "GetChannelBindingFromTls returned null even though OS supposedly supports Extended Protection"); + LogHelper.LogInfo(Logger, "Channel binding retrieved."); return value != null; } - */ public void Dispose() { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs index 93ad2980bc..150ccea190 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs @@ -64,7 +64,7 @@ namespace Microsoft.Net.Http.Server : this(requestStream, userState, callback) { _dataAlreadyRead = dataAlreadyRead; - var boundHandle = requestStream.RequestContext.Server.BoundHandle; + var boundHandle = requestStream.RequestContext.Server.RequestQueue.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, buffer)); _pinnedBuffer = (Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index dbb9f9e557..12af57f093 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -54,7 +54,7 @@ namespace Microsoft.Net.Http.Server CancellationTokenRegistration cancellationRegistration) : this(responseStream, cancellationRegistration) { - var boundHandle = _responseStream.RequestContext.Server.BoundHandle; + var boundHandle = _responseStream.RequestContext.Server.RequestQueue.BoundHandle; object[] objectsToPin; if (buffer.TotalBytes == 0) @@ -117,7 +117,7 @@ namespace Microsoft.Net.Http.Server long? count, bool chunked, CancellationTokenRegistration cancellationRegistration) : this(responseStream, cancellationRegistration) { - var boundHandle = responseStream.RequestContext.Server.BoundHandle; + var boundHandle = responseStream.RequestContext.Server.RequestQueue.BoundHandle; int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. #if NETSTANDARD1_3 diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index 9f1ba26423..91eb95af0b 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -270,7 +270,7 @@ namespace Microsoft.Net.Http.Server IntPtr infoptr = new IntPtr(&timeoutinfo); - _server.SetUrlGroupProperty( + _server.UrlGroup.SetProperty( UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty, infoptr, (uint)TimeoutLimitSize); } diff --git a/src/Microsoft.Net.Http.Server/UrlPrefix.cs b/src/Microsoft.Net.Http.Server/UrlPrefix.cs index fb4e8c070b..d09b77d08f 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefix.cs @@ -151,7 +151,7 @@ namespace Microsoft.Net.Http.Server else { // This means a port was specified but was invalid or empty. - throw new FormatException("Invalid prefix, invalid port speficification: " + prefix); + throw new FormatException("Invalid prefix, invalid port specified: " + prefix); } } else diff --git a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs index 4e8ee48d60..fb64fa6561 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs @@ -49,7 +49,7 @@ namespace Microsoft.Net.Http.Server var id = _nextId++; if (_webListener.IsListening) { - RegisterPrefix(item.Whole, id); + _webListener.UrlGroup.RegisterPrefix(item.Whole, id); } _prefixes.Add(id, item); } @@ -108,7 +108,7 @@ namespace Microsoft.Net.Http.Server id = pair.Key; if (_webListener.IsListening) { - UnregisterPrefix(pair.Value.Whole); + _webListener.UrlGroup.UnregisterPrefix(pair.Value.Whole); } } } @@ -142,7 +142,7 @@ namespace Microsoft.Net.Http.Server foreach (var pair in _prefixes) { // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. - RegisterPrefix(pair.Value.Whole, pair.Key); + _webListener.UrlGroup.RegisterPrefix(pair.Value.Whole, pair.Key); } } } @@ -155,51 +155,9 @@ namespace Microsoft.Net.Http.Server foreach (var prefix in _prefixes.Values) { // ignore possible failures - UnregisterPrefix(prefix.Whole); + _webListener.UrlGroup.UnregisterPrefix(prefix.Whole); } } } - - private void RegisterPrefix(string uriPrefix, int contextId) - { - LogHelper.LogInfo(_webListener.Logger, "Listening on prefix: " + uriPrefix); - - uint statusCode = - UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup( - _webListener.UrlGroupId, - uriPrefix, - (ulong)contextId, - 0); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS) - { - throw new WebListenerException((int)statusCode, String.Format(Resources.Exception_PrefixAlreadyRegistered, uriPrefix)); - } - else - { - throw new WebListenerException((int)statusCode); - } - } - } - - private bool UnregisterPrefix(string uriPrefix) - { - uint statusCode = 0; - LogHelper.LogInfo(_webListener.Logger, "Stop listening on prefix: " + uriPrefix); - - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup( - _webListener.UrlGroupId, - uriPrefix, - 0); - - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) - { - return false; - } - return true; - } } } \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 23f48fcdde..8a7744f269 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -22,14 +22,10 @@ //------------------------------------------------------------------------------ using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using System.Security.Authentication.ExtendedProtection; -using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -41,10 +37,6 @@ namespace Microsoft.Net.Http.Server public sealed class WebListener : IDisposable { private const long DefaultRequestQueueLength = 1000; // Http.sys default. - private static readonly int RequestChannelBindStatusSize = - Marshal.SizeOf(); - private static readonly int BindingInfoSize = - Marshal.SizeOf(); // Win8# 559317 fixed a bug in Http.sys's HttpReceiveClientCertificate method. // Without this fix IOCP callbacks were not being called although ERROR_IO_PENDING was @@ -61,20 +53,17 @@ namespace Microsoft.Net.Http.Server // 0.5 seconds per request. Respond with a 400 Bad Request. private const int UnknownHeaderLimit = 1000; - private readonly ConcurrentDictionary _connectionCancellationTokens; - private ILogger _logger; - private SafeHandle _requestQueueHandle; - private ThreadPoolBoundHandle _boundHandle; private volatile State _state; // m_State is set only within lock blocks, but often read outside locks. private bool _ignoreWriteExceptions; - private HttpServerSessionHandle _serverSessionHandle; - private ulong _urlGroupId; + private ServerSession _serverSession; + private UrlGroup _urlGroup; + private RequestQueue _requestQueue; private TimeoutManager _timeoutManager; private AuthenticationManager _authManager; - private bool _v2Initialized; + private DisconnectListener _disconnectListener; private object _internalLock; @@ -108,7 +97,33 @@ namespace Microsoft.Net.Http.Server _urlPrefixes = new UrlPrefixCollection(this); _timeoutManager = new TimeoutManager(this); _authManager = new AuthenticationManager(this); - _connectionCancellationTokens = new ConcurrentDictionary(); + + // V2 initialization sequence: + // 1. Create server session + // 2. Create url group + // 3. Create request queue - Done in Start() + // 4. Add urls to url group - Done in Start() + // 5. Attach request queue to url group - Done in Start() + + try + { + _serverSession = new ServerSession(); + + _urlGroup = new UrlGroup(_serverSession, _logger); + + _requestQueue = new RequestQueue(_urlGroup, _logger); + + _disconnectListener = new DisconnectListener(_requestQueue, _logger); + } + catch (Exception exception) + { + // If Url group or request queue creation failed, close server session before throwing. + _requestQueue?.Dispose(); + _urlGroup?.Dispose(); + _serverSession?.Dispose(); + LogHelper.LogException(_logger, ".Ctor", exception); + throw; + } } internal enum State @@ -134,22 +149,19 @@ namespace Microsoft.Net.Http.Server set { _bufferResponses = value; } } - internal SafeHandle RequestQueueHandle + internal UrlGroup UrlGroup { - get - { - return _requestQueueHandle; - } + get { return _urlGroup; } } - internal ThreadPoolBoundHandle BoundHandle + internal RequestQueue RequestQueue { - get { return _boundHandle; } + get { return _requestQueue; } } - internal ulong UrlGroupId + internal DisconnectListener DisconnectListener { - get { return _urlGroupId; } + get { return _disconnectListener; } } /// @@ -157,46 +169,27 @@ namespace Microsoft.Net.Http.Server /// public TimeoutManager TimeoutManager { - get - { - ValidateV2Property(); - Debug.Assert(_timeoutManager != null, "Timeout manager is not assigned"); - return _timeoutManager; - } + get { return _timeoutManager; } } public AuthenticationManager AuthenticationManager { - get - { - ValidateV2Property(); - Debug.Assert(_authManager != null, "Auth manager is not assigned"); - return _authManager; - } + get { return _authManager; } } internal static bool IsSupported { - get - { - return UnsafeNclNativeMethods.HttpApi.Supported; - } + get { return UnsafeNclNativeMethods.HttpApi.Supported; } } public bool IsListening { - get - { - return _state == State.Started; - } + get { return _state == State.Started; } } internal bool IgnoreWriteExceptions { - get - { - return _ignoreWriteExceptions; - } + get { return _ignoreWriteExceptions; } set { CheckDisposed(); @@ -210,6 +203,7 @@ namespace Microsoft.Net.Http.Server /// public void SetRequestQueueLimit(long limit) { + CheckDisposed(); if (limit <= 0) { throw new ArgumentOutOfRangeException("limit", limit, string.Empty); @@ -221,140 +215,18 @@ namespace Microsoft.Net.Http.Server } _requestQueueLength = limit; - - SetRequestQueueLimit(); - } - - private unsafe void SetRequestQueueLimit() - { - // The listener must be active for this to work. Call from Start after activating. - if (!IsListening || !_requestQueueLength.HasValue) - { - return; - } - - long length = _requestQueueLength.Value; - uint result = UnsafeNclNativeMethods.HttpApi.HttpSetRequestQueueProperty(_requestQueueHandle, - UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, - new IntPtr((void*)&length), (uint)Marshal.SizeOf(), 0, IntPtr.Zero); - - if (result != 0) - { - throw new WebListenerException((int)result); - } - } - - private void ValidateV2Property() - { - // Make sure that calling CheckDisposed and SetupV2Config is an atomic operation. This - // avoids race conditions if the listener is aborted/closed after CheckDisposed(), but - // before SetupV2Config(). - lock (_internalLock) - { - CheckDisposed(); - SetupV2Config(); - } - } - - internal void SetUrlGroupProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize) - { - ValidateV2Property(); - uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; - - Debug.Assert(_urlGroupId != 0, "SetUrlGroupProperty called with invalid url group id"); - Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); - - // Set the url group property using Http Api. - - statusCode = UnsafeNclNativeMethods.HttpApi.HttpSetUrlGroupProperty( - _urlGroupId, property, info, infosize); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - WebListenerException exception = new WebListenerException((int)statusCode); - LogHelper.LogException(_logger, "SetUrlGroupProperty", exception); - throw exception; - } - } - - private IntPtr DangerousGetHandle() - { - return _requestQueueHandle.DangerousGetHandle(); - } - - private unsafe void SetupV2Config() - { - uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; - ulong id = 0; - - // If we have already initialized V2 config, then nothing to do. - - if (_v2Initialized) - { - return; - } - - // V2 initialization sequence: - // 1. Create server session - // 2. Create url group - // 3. Create request queue - Done in Start() - // 4. Add urls to url group - Done in Start() - // 5. Attach request queue to url group - Done in Start() - - try - { - statusCode = UnsafeNclNativeMethods.HttpApi.HttpCreateServerSession( - UnsafeNclNativeMethods.HttpApi.Version, &id, 0); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - throw new WebListenerException((int)statusCode); - } - - Debug.Assert(id != 0, "Invalid id returned by HttpCreateServerSession"); - - _serverSessionHandle = new HttpServerSessionHandle(id); - - id = 0; - statusCode = UnsafeNclNativeMethods.HttpApi.HttpCreateUrlGroup( - _serverSessionHandle.DangerousGetServerSessionId(), &id, 0); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - throw new WebListenerException((int)statusCode); - } - - Debug.Assert(id != 0, "Invalid id returned by HttpCreateUrlGroup"); - _urlGroupId = id; - - _v2Initialized = true; - } - catch (Exception exception) - { - // If V2 initialization fails, we mark object as unusable. - _state = State.Disposed; - // If Url group or request queue creation failed, close server session before throwing. - if (_serverSessionHandle != null) - { - _serverSessionHandle.Dispose(); - } - LogHelper.LogException(_logger, "SetupV2Config", exception); - throw; - } + _requestQueue.SetLengthLimit(_requestQueueLength.Value); } public void Start() { CheckDisposed(); - // TODO: _logger = LogHelper.CreateLogger(loggerFactory, typeof(OwinWebListener)); LogHelper.LogInfo(_logger, "Start"); - // Make sure there are no race conditions between Start/Stop/Abort/Close/Dispose and - // calls to SetupV2Config: Start needs to setup all resources (esp. in V2 where besides - // the request handle, there is also a server session and a Url group. Abort/Stop must - // not interfere while Start is allocating those resources. The lock also makes sure - // all methods changing state can read and change the state in an atomic way. + // Make sure there are no race conditions between Start/Stop/Abort/Close/Dispose. + // Start needs to setup all resources. Abort/Stop must not interfere while Start is + // allocating those resources. lock (_internalLock) { try @@ -365,12 +237,7 @@ namespace Microsoft.Net.Http.Server return; } - // SetupV2Config() is not called in the ctor, because it may throw. This would - // be a regression since in v1 the ctor never threw. Besides, ctors should do - // minimal work according to the framework design guidelines. - SetupV2Config(); - CreateRequestQueueHandle(); - AttachRequestQueueToUrlGroup(); + _requestQueue.AttachToUrlGroup(); // All resources are set up correctly. Now add all prefixes. try @@ -380,99 +247,24 @@ namespace Microsoft.Net.Http.Server catch (WebListenerException) { // If an error occurred while adding prefixes, free all resources allocated by previous steps. - DetachRequestQueueFromUrlGroup(); + _requestQueue.DetachFromUrlGroup(); throw; } _state = State.Started; - - SetRequestQueueLimit(); } catch (Exception exception) { // Make sure the HttpListener instance can't be used if Start() failed. _state = State.Disposed; - CloseRequestQueueHandle(); - CleanupV2Config(); + DisposeInternal(); LogHelper.LogException(_logger, "Start", exception); throw; } } } - private void CleanupV2Config() - { - // If we never setup V2, just return. - if (!_v2Initialized) - { - return; - } - - // V2 stopping sequence: - // 1. Detach request queue from url group - Done in Stop()/Abort() - // 2. Remove urls from url group - Done in Stop() - // 3. Close request queue - Done in Stop()/Abort() - // 4. Close Url group. - // 5. Close server session. - - Debug.Assert(_urlGroupId != 0, "HttpCloseUrlGroup called with invalid url group id"); - - uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpCloseUrlGroup(_urlGroupId); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - LogHelper.LogError(_logger, "CleanupV2Config", "Result: " + statusCode); - } - _urlGroupId = 0; - - Debug.Assert(_serverSessionHandle != null, "ServerSessionHandle is null in CloseV2Config"); - Debug.Assert(!_serverSessionHandle.IsInvalid, "ServerSessionHandle is invalid in CloseV2Config"); - - _serverSessionHandle.Dispose(); - } - - private unsafe void AttachRequestQueueToUrlGroup() - { - // Set the association between request queue and url group. After this, requests for registered urls will - // get delivered to this request queue. - - UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO info = new UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO(); - info.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; - info.RequestQueueHandle = DangerousGetHandle(); - - IntPtr infoptr = new IntPtr(&info); - - SetUrlGroupProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, - infoptr, (uint)BindingInfoSize); - } - - private unsafe void DetachRequestQueueFromUrlGroup() - { - Debug.Assert(_urlGroupId != 0, "DetachRequestQueueFromUrlGroup can't detach using Url group id 0."); - - // Break the association between request queue and url group. After this, requests for registered urls - // will get 503s. - // Note that this method may be called multiple times (Stop() and then Abort()). This - // is fine since http.sys allows to set HttpServerBindingProperty multiple times for valid - // Url groups. - - UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO info = new UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO(); - info.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; - info.RequestQueueHandle = IntPtr.Zero; - - IntPtr infoptr = new IntPtr(&info); - - uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpSetUrlGroupProperty(_urlGroupId, - UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, - infoptr, (uint)BindingInfoSize); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - LogHelper.LogError(_logger, "DetachRequestQueueFromUrlGroup", "Result: " + statusCode); - } - } - - internal void Stop() + private void Stop() { try { @@ -488,13 +280,7 @@ namespace Microsoft.Net.Http.Server _state = State.Stopped; - DetachRequestQueueFromUrlGroup(); - - // Even though it would be enough to just detach the request queue in v2, in order to - // keep app compat with earlier versions of the framework, we need to close the request queue. - // This will make sure that pending GetContext() calls will complete and throw an exception. Just - // detaching the url group from the request queue would not cause GetContext() to return. - CloseRequestQueueHandle(); + _requestQueue.DetachFromUrlGroup(); } } catch (Exception exception) @@ -504,46 +290,6 @@ namespace Microsoft.Net.Http.Server } } - private unsafe void CreateRequestQueueHandle() - { - uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; - - HttpRequestQueueV2Handle requestQueueHandle = null; - statusCode = - UnsafeNclNativeMethods.SafeNetHandles.HttpCreateRequestQueue( - UnsafeNclNativeMethods.HttpApi.Version, null, null, 0, out requestQueueHandle); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - throw new WebListenerException((int)statusCode); - } - - // Disabling callbacks when IO operation completes synchronously (returns ErrorCodes.ERROR_SUCCESS) - if (SkipIOCPCallbackOnSuccess && - !UnsafeNclNativeMethods.SetFileCompletionNotificationModes( - requestQueueHandle, - UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipCompletionPortOnSuccess | - UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipSetEventOnHandle)) - { - throw new WebListenerException(Marshal.GetLastWin32Error()); - } - - _requestQueueHandle = requestQueueHandle; - _boundHandle = ThreadPoolBoundHandle.BindHandle(_requestQueueHandle); - } - - private unsafe void CloseRequestQueueHandle() - { - if ((_requestQueueHandle != null) && (!_requestQueueHandle.IsInvalid)) - { - _requestQueueHandle.Dispose(); - } - if (_boundHandle != null) - { - _boundHandle.Dispose(); - } - } - /// /// Stop the server and clean up. /// @@ -571,7 +317,7 @@ namespace Microsoft.Net.Http.Server LogHelper.LogInfo(_logger, "Dispose"); Stop(); - CleanupV2Config(); + DisposeInternal(); } catch (Exception exception) { @@ -585,6 +331,25 @@ namespace Microsoft.Net.Http.Server } } + private void DisposeInternal() + { + // V2 stopping sequence: + // 1. Detach request queue from url group - Done in Stop()/Abort() + // 2. Remove urls from url group - Done in Stop() + // 3. Close request queue - Done in Stop()/Abort() + // 4. Close Url group. + // 5. Close server session. + + _requestQueue.Dispose(); + + _urlGroup.Dispose(); + + Debug.Assert(_serverSession != null, "ServerSessionHandle is null in CloseV2Config"); + Debug.Assert(!_serverSession.Id.IsInvalid, "ServerSessionHandle is invalid in CloseV2Config"); + + _serverSession.Dispose(); + } + internal unsafe bool ValidateRequest(NativeRequestContext requestMemory) { // Block potential DOS attacks @@ -624,7 +389,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) { - // someother bad error, possible(?) return values are: + // some other bad error, possible(?) return values are: // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED asyncResult.Dispose(); throw new WebListenerException((int)statusCode); @@ -639,101 +404,6 @@ namespace Microsoft.Net.Http.Server return asyncResult.Task; } - internal CancellationToken RegisterForDisconnectNotification(RequestContext requestContext) - { - try - { - // Create exactly one CancellationToken per connection. - ulong connectionId = requestContext.Request.ConnectionId; - return GetConnectionCancellation(connectionId); - } - catch (Win32Exception exception) - { - LogHelper.LogException(_logger, "RegisterForDisconnectNotification", exception); - return CancellationToken.None; - } - } - - private CancellationToken GetConnectionCancellation(ulong connectionId) - { - // Read case is performance sensitive - ConnectionCancellation cancellation; - if (!_connectionCancellationTokens.TryGetValue(connectionId, out cancellation)) - { - cancellation = GetCreatedConnectionCancellation(connectionId); - } - return cancellation.GetCancellationToken(connectionId); - } - - private ConnectionCancellation GetCreatedConnectionCancellation(ulong connectionId) - { - // Race condition on creation has no side effects - ConnectionCancellation cancellation = new ConnectionCancellation(this); - return _connectionCancellationTokens.GetOrAdd(connectionId, cancellation); - } - - private unsafe CancellationToken CreateDisconnectToken(ulong connectionId) - { - // Debug.WriteLine("Server: Registering connection for disconnect for connection ID: " + connectionId); - - // Create a nativeOverlapped callback so we can register for disconnect callback - var cts = new CancellationTokenSource(); - - SafeNativeOverlapped nativeOverlapped = null; - nativeOverlapped = new SafeNativeOverlapped(_boundHandle, _boundHandle.AllocateNativeOverlapped( - (errorCode, numBytes, overlappedPtr) => - { - // Debug.WriteLine("Server: http.sys disconnect callback fired for connection ID: " + connectionId); - - // Free the overlapped - nativeOverlapped.Dispose(); - - // Pull the token out of the list and Cancel it. - ConnectionCancellation token; - _connectionCancellationTokens.TryRemove(connectionId, out token); - try - { - cts.Cancel(); - } - catch (AggregateException exception) - { - LogHelper.LogException(_logger, "CreateDisconnectToken::Disconnected", exception); - } - - cts.Dispose(); - }, - null, null)); - - uint statusCode; - try - { - statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnectEx(requestQueueHandle: _requestQueueHandle, - connectionId: connectionId, reserved: 0, overlapped: nativeOverlapped); - } - catch (Win32Exception exception) - { - statusCode = (uint)exception.NativeErrorCode; - LogHelper.LogException(_logger, "CreateDisconnectToken", exception); - } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING && - statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - // We got an unknown result so return a None - // TODO: return a canceled token? - return CancellationToken.None; - } - - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously - callback won't be called to signal completion. - // TODO: return a canceled token? - return CancellationToken.None; - } - - return cts.Token; - } - private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode, IList authChallenges) { UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2(); @@ -809,7 +479,7 @@ namespace Microsoft.Net.Http.Server statusCode = UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( - _requestQueueHandle, + _requestQueue.Handle, requestId, 0, &httpResponse, @@ -824,7 +494,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { // if we fail to send a 401 something's seriously wrong, abort the request - RequestContext.CancelRequest(_requestQueueHandle, requestId); + RequestContext.CancelRequest(_requestQueue.Handle, requestId); } } finally @@ -842,100 +512,6 @@ namespace Microsoft.Net.Http.Server } } - private static int GetTokenOffsetFromBlob(IntPtr blob) - { - Debug.Assert(blob != IntPtr.Zero); - IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); - Debug.Assert(tokenPointer != IntPtr.Zero); - return (int)IntPtrHelper.Subtract(tokenPointer, blob); - } - - private static int GetTokenSizeFromBlob(IntPtr blob) - { - Debug.Assert(blob != IntPtr.Zero); - return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); - } - - internal ChannelBinding GetChannelBinding(ulong connectionId, bool isSecureConnection) - { - if (!isSecureConnection) - { - LogHelper.LogInfo(_logger, "Channel binding is not supported for HTTP."); - return null; - } - - ChannelBinding result = GetChannelBindingFromTls(connectionId); - - Debug.Assert(result != null, "GetChannelBindingFromTls returned null even though OS supposedly supports Extended Protection"); - LogHelper.LogInfo(_logger, "Channel binding retrieved."); - return result; - } - - private unsafe ChannelBinding GetChannelBindingFromTls(ulong connectionId) - { - // +128 since a CBT is usually <128 thus we need to call HRCC just once. If the CBT - // is >128 we will get ERROR_MORE_DATA and call again - int size = RequestChannelBindStatusSize + 128; - - Debug.Assert(size >= 0); - - byte[] blob = null; - SafeLocalFreeChannelBinding token = null; - - uint bytesReceived = 0; - uint statusCode; - - do - { - blob = new byte[size]; - fixed (byte* blobPtr = blob) - { - // Http.sys team: ServiceName will always be null if - // HTTP_RECEIVE_SECURE_CHANNEL_TOKEN flag is set. - statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( - RequestQueueHandle, - connectionId, - (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN, - blobPtr, - (uint)size, - &bytesReceived, - SafeNativeOverlapped.Zero); - - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) - { - int tokenOffset = GetTokenOffsetFromBlob((IntPtr)blobPtr); - int tokenSize = GetTokenSizeFromBlob((IntPtr)blobPtr); - Debug.Assert(tokenSize < Int32.MaxValue); - - token = SafeLocalFreeChannelBinding.LocalAlloc(tokenSize); - - Marshal.Copy(blob, tokenOffset, token.DangerousGetHandle(), tokenSize); - } - else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) - { - int tokenSize = GetTokenSizeFromBlob((IntPtr)blobPtr); - Debug.Assert(tokenSize < Int32.MaxValue); - - size = RequestChannelBindStatusSize + tokenSize; - } - else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER) - { - LogHelper.LogError(_logger, "GetChannelBindingFromTls", "Channel binding is not supported."); - return null; // old schannel library which doesn't support CBT - } - else - { - // It's up to the consumer to fail if the missing ChannelBinding matters to them. - LogHelper.LogException(_logger, "GetChannelBindingFromTls", new WebListenerException((int)statusCode)); - break; - } - } - } - while (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); - - return token; - } - internal void CheckDisposed() { if (_state == State.Disposed) @@ -943,35 +519,5 @@ namespace Microsoft.Net.Http.Server throw new ObjectDisposedException(this.GetType().FullName); } } - - private class ConnectionCancellation - { - private readonly WebListener _parent; - private volatile bool _initialized; // Must be volatile because initialization is synchronized - private CancellationToken _cancellationToken; - - public ConnectionCancellation(WebListener parent) - { - _parent = parent; - } - - internal CancellationToken GetCancellationToken(ulong connectionId) - { - // Initialized case is performance sensitive - if (_initialized) - { - return _cancellationToken; - } - return InitializeCancellationToken(connectionId); - } - - private CancellationToken InitializeCancellationToken(ulong connectionId) - { - object syncObject = this; -#pragma warning disable 420 // Disable warning about volatile by reference since EnsureInitialized does volatile operations - return LazyInitializer.EnsureInitialized(ref _cancellationToken, ref _initialized, ref syncObject, () => _parent.CreateDisconnectToken(connectionId)); -#pragma warning restore 420 - } - } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 6bfa2f0085..4073056695 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -787,7 +787,7 @@ namespace Microsoft.Net.Http.Server // Responses can be cached for requests with cache-control: no-cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_RequestCacheControlNoCache_Cached() { string address; From 235ac59551daf3ac46860814699eade72e89cf23 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 27 Jul 2016 10:29:15 -0700 Subject: [PATCH 364/597] API cleaup, organization --- samples/HelloWorld/Program.cs | 4 +- samples/HotAddSample/Startup.cs | 2 - samples/SelfHostServer/Startup.cs | 1 - .../AuthenticationHandler.cs | 4 +- .../FeatureContext.cs | 4 +- .../Internal/WebListenerOptionsSetup.cs | 1 - .../MessagePump.cs | 36 +-- .../Properties/AssemblyInfo.cs | 2 + .../WebHostBuilderWebListenerExtensions.cs | 3 - .../WebListenerOptions.cs | 9 +- .../AuthenticationManager.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 29 +- .../RequestProcessing/ClientCertLoader.cs | 12 +- .../RequestProcessing/Request.cs | 275 ++++-------------- .../RequestProcessing/RequestContext.cs | 128 +++----- .../RequestProcessing/RequestStream.cs | 31 +- .../RequestProcessing/Response.cs | 116 ++++---- .../RequestProcessing/ResponseStream.cs | 42 +-- .../TimeoutManager.cs | 80 ++--- src/Microsoft.Net.Http.Server/WebListener.cs | 127 ++++---- .../project.json | 4 + .../AuthenticationTests.cs | 36 +-- .../HttpsTests.cs | 10 +- .../OpaqueUpgradeTests.cs | 8 +- .../RequestBodyTests.cs | 26 +- .../RequestHeaderTests.cs | 6 +- .../RequestTests.cs | 10 +- .../ResponseBodyTests.cs | 38 +-- .../ResponseCachingTests.cs | 86 +++--- .../ResponseHeaderTests.cs | 34 +-- .../ResponseSendFileTests.cs | 26 +- .../ResponseTests.cs | 12 +- .../ServerTests.cs | 24 +- .../WebSocketTests.cs | 6 +- 34 files changed, 495 insertions(+), 739 deletions(-) diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 0285c349fa..7e74bf87d0 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -18,13 +18,13 @@ namespace HelloWorld { using (WebListener listener = new WebListener()) { - listener.UrlPrefixes.Add(UrlPrefix.Create("http://localhost:8080")); + listener.UrlPrefixes.Add("http://localhost:8080"); listener.Start(); Console.WriteLine("Running..."); while (true) { - RequestContext context = await listener.GetContextAsync(); + RequestContext context = await listener.AcceptAsync(); Console.WriteLine("Accepted"); // Context: diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index d3b7753f80..1fa57b5606 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -2,8 +2,6 @@ using System; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 3e3d72be83..81875a0af2 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -5,7 +5,6 @@ using System.Threading; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.WebListener; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs index b1f9aec312..bd1df634e9 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Server.WebListener internal AuthenticationHandler(RequestContext requestContext) { _requestContext = requestContext; - _authSchemes = requestContext.AuthenticationChallenges; + _authSchemes = requestContext.Response.AuthenticationChallenges; _customChallenges = AuthenticationSchemes.None; } @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } // A challenge was issued, it overrides any pre-set auth types. - _requestContext.AuthenticationChallenges = _customChallenges; + _requestContext.Response.AuthenticationChallenges = _customChallenges; return Task.FromResult(0); } diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index ec906fdf37..61109f123f 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Server.WebListener internal ITlsConnectionFeature GetTlsConnectionFeature() { - return Request.IsSecureConnection ? this : null; + return Request.IsHttps ? this : null; } byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId() @@ -338,7 +338,7 @@ namespace Microsoft.AspNetCore.Server.WebListener internal ITlsTokenBindingFeature GetTlsTokenBindingFeature() { - return Request.IsSecureConnection ? this : null; + return Request.IsHttps ? this : null; } void IHttpBufferingFeature.DisableRequestBuffering() diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs b/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs index 5e27bbf8c2..eeba2f8b91 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs @@ -15,7 +15,6 @@ // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -using System; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs index 554a090c8d..4ba6599e2a 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs @@ -29,10 +29,8 @@ using Microsoft.Net.Http.Server; namespace Microsoft.AspNetCore.Server.WebListener { - public class MessagePump : IServer + internal class MessagePump : IServer { - private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; - private readonly Microsoft.Net.Http.Server.WebListener _listener; private readonly ILogger _logger; @@ -48,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.WebListener private readonly ServerAddressesFeature _serverAddresses; - public MessagePump(IOptions options, ILoggerFactory loggerFactory) + internal MessagePump(IOptions options, ILoggerFactory loggerFactory) { if (options == null) { @@ -66,32 +64,17 @@ namespace Microsoft.AspNetCore.Server.WebListener Features.Set(_serverAddresses); _processRequest = new Action(ProcessRequestAsync); - _maxAccepts = DefaultMaxAccepts; + _maxAccepts = options.Value?.MaxAccepts ?? WebListenerOptions.DefaultMaxAccepts; + EnableResponseCaching = options.Value?.EnableResponseCaching ?? true; _shutdownSignal = new ManualResetEvent(false); } - public Microsoft.Net.Http.Server.WebListener Listener + internal Microsoft.Net.Http.Server.WebListener Listener { get { return _listener; } } - internal int MaxAccepts - { - get - { - return _maxAccepts; - } - set - { - _maxAccepts = value; - if (_listener.IsListening) - { - ActivateRequestProcessingLimits(); - } - } - } - - internal bool EnableResponseCaching { get; set; } = true; + internal bool EnableResponseCaching { get; set; } public IFeatureCollection Features { get; } @@ -123,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.WebListener private void ActivateRequestProcessingLimits() { - for (int i = _acceptorCounts; i < MaxAccepts; i++) + for (int i = _acceptorCounts; i < _maxAccepts; i++) { ProcessRequestsWorker(); } @@ -136,13 +119,13 @@ namespace Microsoft.AspNetCore.Server.WebListener private async void ProcessRequestsWorker() { int workerIndex = Interlocked.Increment(ref _acceptorCounts); - while (!_stopping && workerIndex <= MaxAccepts) + while (!_stopping && workerIndex <= _maxAccepts) { // Receive a request RequestContext requestContext; try { - requestContext = await _listener.GetContextAsync().SupressContext(); + requestContext = await _listener.AcceptAsync().SupressContext(); } catch (Exception exception) { @@ -237,7 +220,6 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - public void Dispose() { _stopping = true; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs index 79eeb571ef..17fae786fd 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs @@ -3,9 +3,11 @@ using System.Reflection; using System.Resources; +using System.Runtime.CompilerServices; [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyCompany("Microsoft Corporation.")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft ASP.NET Core")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.WebListener.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs index 51c658b9f0..f314cb1c4a 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs @@ -16,9 +16,6 @@ // permissions and limitations under the License. using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Server.WebListener; using Microsoft.AspNetCore.Server.WebListener.Internal; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs index 814314e9a2..9613f6d468 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs @@ -16,14 +16,17 @@ // permissions and limitations under the License. using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Microsoft.AspNetCore.Server.WebListener { public class WebListenerOptions { + internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; + public Microsoft.Net.Http.Server.WebListener Listener { get; set; } = new Microsoft.Net.Http.Server.WebListener(); + + public int MaxAccepts { get; set; } = DefaultMaxAccepts; + + public bool EnableResponseCaching { get; set; } = true; } } diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 877e8077ed..32d7ee2e69 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -144,7 +144,7 @@ namespace Microsoft.Net.Http.Server internal void SetAuthenticationChallenge(RequestContext context) { - IList challenges = GenerateChallenges(context.AuthenticationChallenges); + IList challenges = GenerateChallenges(context.Response.AuthenticationChallenges); if (challenges.Count > 0) { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index b5a4162058..b9e2c71f72 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -1105,7 +1105,8 @@ namespace Microsoft.Net.Http.Server } } - private static unsafe string GetVerb(HTTP_REQUEST* request, long fixup) + // This requires the HTTP_REQUEST to still be pinned in its original location. + internal static unsafe string GetVerb(HTTP_REQUEST* request) { string verb = null; @@ -1115,31 +1116,7 @@ namespace Microsoft.Net.Http.Server } else if (request->Verb == HTTP_VERB.HttpVerbUnknown && request->pUnknownVerb != null) { - verb = HeaderEncoding.GetString(request->pUnknownVerb + fixup, request->UnknownVerbLength); - } - - return verb; - } - - internal static unsafe string GetVerb(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - return GetVerb((HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress); - } - } - - internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) - { - // Return value. - HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown; - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) - { - verb = request->Verb; - } + verb = HeaderEncoding.GetString(request->pUnknownVerb, request->UnknownVerbLength); } return verb; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs index 62197abf1f..63df5bdc89 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs @@ -67,10 +67,12 @@ namespace Microsoft.Net.Http.Server if (cancellationToken.CanBeCanceled) { - _cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + _cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); } } + internal SafeHandle RequestQueueHandle => _requestContext.Server.RequestQueue.Handle; + internal X509Certificate2 ClientCert { get @@ -184,8 +186,8 @@ namespace Microsoft.Net.Http.Server uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( - RequestContext.RequestQueueHandle, - RequestContext.Request.ConnectionId, + RequestQueueHandle, + RequestContext.Request.UConnectionId, (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, RequestBlob, size, @@ -263,8 +265,8 @@ namespace Microsoft.Net.Http.Server uint bytesReceived = 0; errorCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( - requestContext.RequestQueueHandle, - requestContext.Request.ConnectionId, + requestContext.Server.RequestQueue.Handle, + requestContext.Request.UConnectionId, (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, asyncResult._memoryBlob, asyncResult._size, diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 72bc826284..659ec35310 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -22,48 +22,25 @@ //------------------------------------------------------------------------------ using System; -using System.Collections; -using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; -using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { public sealed class Request { - private RequestContext _requestContext; private NativeRequestContext _nativeRequestContext; - private ulong _requestId; - private ulong _connectionId; - private ulong _contextId; - - private SslStatus _sslStatus; - - private string _httpMethod; - private Version _httpVersion; - - // private Uri _requestUri; - private string _rawUrl; - private string _cookedUrlHost; - private string _cookedUrlPath; - private string _cookedUrlQuery; - private string _pathBase; - private string _path; - private X509Certificate2 _clientCert; private byte[] _providedTokenBindingId; private byte[] _referredTokenBindingId; - private HeaderCollection _headers; private BoundaryType _contentBoundaryType; private long? _contentLength; private Stream _nativeStream; @@ -71,116 +48,90 @@ namespace Microsoft.Net.Http.Server private SocketAddress _localEndPoint; private SocketAddress _remoteEndPoint; - private ClaimsPrincipal _user; - private bool _isDisposed = false; - internal unsafe Request(RequestContext httpContext, NativeRequestContext memoryBlob) + internal unsafe Request(RequestContext requestContext, NativeRequestContext memoryBlob) { // TODO: Verbose log - _requestContext = httpContext; + RequestContext = requestContext; _nativeRequestContext = memoryBlob; _contentBoundaryType = BoundaryType.None; // Set up some of these now to avoid refcounting on memory blob later. - _requestId = memoryBlob.RequestBlob->RequestId; - _connectionId = memoryBlob.RequestBlob->ConnectionId; - _contextId = memoryBlob.RequestBlob->UrlContext; - _sslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure : + RequestId = memoryBlob.RequestBlob->RequestId; + UConnectionId = memoryBlob.RequestBlob->ConnectionId; + SslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure : memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : SslStatus.ClientCert; if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0) { - _rawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); + RawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); } UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl; if (cookedUrl.pHost != null && cookedUrl.HostLength > 0) { - _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2); + // TODO: Unused + // _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2); } + var cookedUrlPath = string.Empty; if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0) { - _cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); + cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); } + QueryString = string.Empty; if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0) { - _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); + QueryString = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } - UrlPrefix prefix = httpContext.Server.UrlPrefixes.GetPrefix((int)_contextId); - string originalPath = RequestPath; + var prefix = requestContext.Server.UrlPrefixes.GetPrefix((int)memoryBlob.RequestBlob->UrlContext); + var originalPath = RequestUriBuilder.GetRequestPath(RawUrl, cookedUrlPath, RequestContext.Logger); // These paths are both unescaped already. if (originalPath.Length == prefix.Path.Length - 1) { // They matched exactly except for the trailing slash. - _pathBase = originalPath; - _path = string.Empty; + PathBase = originalPath; + Path = string.Empty; } else { // url: /base/path, prefix: /base/, base: /base, path: /path // url: /, prefix: /, base: , path: / - _pathBase = originalPath.Substring(0, prefix.Path.Length - 1); - _path = originalPath.Substring(prefix.Path.Length - 1); + PathBase = originalPath.Substring(0, prefix.Path.Length - 1); + Path = originalPath.Substring(prefix.Path.Length - 1); } int major = memoryBlob.RequestBlob->Version.MajorVersion; int minor = memoryBlob.RequestBlob->Version.MinorVersion; if (major == 1 && minor == 1) { - _httpVersion = Constants.V1_1; + ProtocolVersion = Constants.V1_1; } else if (major == 1 && minor == 0) { - _httpVersion = Constants.V1_0; + ProtocolVersion = Constants.V1_0; } else { - _httpVersion = new Version(major, minor); + ProtocolVersion = new Version(major, minor); } - _httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, BufferAlignment, OriginalBlobAddress); - _headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); + KnownMethod = memoryBlob.RequestBlob->Verb; + Method = UnsafeNclNativeMethods.HttpApi.GetVerb(memoryBlob.RequestBlob); + Headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; - _user = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount); + User = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount); GetTlsTokenBindingInfo(); + // Finished directly accessing the HTTP_REQUEST structure. + _nativeRequestContext.ReleasePins(); // TODO: Verbose log parameters } - internal SslStatus SslStatus - { - get - { - return _sslStatus; - } - } - - public ulong ConnectionId - { - get - { - return _connectionId; - } - } - - internal ulong ContextId - { - get { return _contextId; } - } - - internal RequestContext RequestContext - { - get - { - return _requestContext; - } - } - internal byte[] RequestBuffer { get @@ -208,26 +159,19 @@ namespace Microsoft.Net.Http.Server } } - // With the leading ?, if any - public string QueryString - { - get - { - return _cookedUrlQuery ?? string.Empty; - } - set - { - _cookedUrlQuery = value; - } - } + internal ulong UConnectionId { get; } - internal ulong RequestId - { - get - { - return _requestId; - } - } + // No ulongs in public APIs... + public long ConnectionId => (long)UConnectionId; + + internal ulong RequestId { get; } + + private SslStatus SslStatus { get; } + + private RequestContext RequestContext { get; } + + // With the leading ?, if any + public string QueryString { get; } public long? ContentLength { @@ -261,20 +205,13 @@ namespace Microsoft.Net.Http.Server } } - public HeaderCollection Headers - { - get { return _headers; } - } + public HeaderCollection Headers { get; } - public string Method - { - get { return _httpMethod; } - } + private UnsafeNclNativeMethods.HttpApi.HTTP_VERB KnownMethod { get; } - public bool IsHeadMethod - { - get { return string.Equals(_httpMethod, "HEAD", StringComparison.OrdinalIgnoreCase); } - } + public bool IsHeadMethod => KnownMethod == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD; + + public string Method { get; } public Stream Body { @@ -288,39 +225,15 @@ namespace Microsoft.Net.Http.Server } } - public string PathBase - { - get { return _pathBase; } - } + public string PathBase { get; } - public string Path - { - get { return _path; } - } + public string Path { get; } - public bool IsSecureConnection - { - get - { - return _sslStatus != SslStatus.Insecure; - } - } + public bool IsHttps => SslStatus != SslStatus.Insecure; - public string RawUrl - { - get - { - return _rawUrl; - } - } + public string RawUrl { get; } - public Version ProtocolVersion - { - get - { - return _httpVersion; - } - } + public Version ProtocolVersion { get; } public bool HasEntityBody { @@ -358,65 +271,24 @@ namespace Microsoft.Net.Http.Server } } - public IPAddress RemoteIpAddress - { - get { return RemoteEndPoint.GetIPAddress(); } - } + // TODO: Lazy cache? + public IPAddress RemoteIpAddress => RemoteEndPoint.GetIPAddress(); - public IPAddress LocalIpAddress - { - get { return LocalEndPoint.GetIPAddress(); } - } + public IPAddress LocalIpAddress => LocalEndPoint.GetIPAddress(); - public int RemotePort - { - get { return RemoteEndPoint.GetPort(); } - } + public int RemotePort => RemoteEndPoint.GetPort(); - public int LocalPort - { - get { return LocalEndPoint.GetPort(); } - } + public int LocalPort => LocalEndPoint.GetPort(); - public string Scheme - { - get { return IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; } - } + public string Scheme => IsHttps ? Constants.HttpsScheme : Constants.HttpScheme; - internal string RequestPath - { - get - { - return RequestUriBuilder.GetRequestPath(_rawUrl, _cookedUrlPath, RequestContext.Logger); - } - } + // HTTP.Sys allows you to upgrade anything to opaque unless content-length > 0 or chunked are specified. + // TODO: >= Win8 check https://github.com/aspnet/WebListener/issues/215 + internal bool IsUpgradable => !HasEntityBody; - internal bool IsUpgradable - { - get - { - // HTTP.Sys allows you to upgrade anything to opaque unless content-length > 0 or chunked are specified. - return !HasEntityBody; - } - } + public string ContentType => Headers[HttpKnownHeaderNames.ContentType]; - public string ContentType - { - get - { - return Headers[HttpKnownHeaderNames.ContentType]; - } - } - - internal ClaimsPrincipal User - { - get { return _user; } - } - - internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod() - { - return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, BufferAlignment, OriginalBlobAddress); - } + internal ClaimsPrincipal User { get; } // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to @@ -435,7 +307,7 @@ namespace Microsoft.Net.Http.Server } cancellationToken.ThrowIfCancellationRequested(); - ClientCertLoader certLoader = new ClientCertLoader(RequestContext, cancellationToken); + var certLoader = new ClientCertLoader(RequestContext, cancellationToken); try { await certLoader.LoadClientCertificateAsync().SupressContext(); @@ -489,40 +361,19 @@ namespace Microsoft.Net.Http.Server } } - // Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be - // disposed. - internal void DetachBlob(NativeRequestContext memoryBlob) - { - if (memoryBlob != null && (object)memoryBlob == (object)_nativeRequestContext) - { - _nativeRequestContext = null; - } - } - - // Finalizes ownership of the memory blob. DetachBlob can't be called after this. - internal void ReleasePins() - { - _nativeRequestContext.ReleasePins(); - } - // should only be called from RequestContext internal void Dispose() { // TODO: Verbose log _isDisposed = true; - NativeRequestContext memoryBlob = _nativeRequestContext; - if (memoryBlob != null) - { - memoryBlob.Dispose(); - _nativeRequestContext = null; - } + _nativeRequestContext.Dispose(); if (_nativeStream != null) { _nativeStream.Dispose(); } } - internal void CheckDisposed() + private void CheckDisposed() { if (_isDisposed) { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index c0fede1e33..99c5221a82 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -23,9 +23,7 @@ using System; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; using System.Security.Claims; using System.Threading; @@ -36,47 +34,31 @@ namespace Microsoft.Net.Http.Server { public sealed class RequestContext : IDisposable { - internal static readonly Action AbortDelegate = Abort; + private static readonly Action AbortDelegate = Abort; - private WebListener _server; - private Request _request; - private Response _response; private NativeRequestContext _memoryBlob; - private bool _disposed; private CancellationTokenSource _requestAbortSource; private CancellationToken? _disconnectToken; + private bool _disposed; internal RequestContext(WebListener server, NativeRequestContext memoryBlob) { // TODO: Verbose log - _server = server; + Server = server; _memoryBlob = memoryBlob; - _request = new Request(this, _memoryBlob); - _response = new Response(this); - _request.ReleasePins(); - AuthenticationChallenges = server.AuthenticationManager.AuthenticationSchemes & ~AuthenticationSchemes.AllowAnonymous; + Request = new Request(this, _memoryBlob); + Response = new Response(this); } - public Request Request - { - get - { - return _request; - } - } + internal WebListener Server { get; } - public Response Response - { - get - { - return _response; - } - } + internal ILogger Logger => Server.Logger; - public ClaimsPrincipal User - { - get { return _request.User; } - } + public Request Request { get; } + + public Response Response { get; } + + public ClaimsPrincipal User => Request.User; public CancellationToken DisconnectToken { @@ -86,7 +68,7 @@ namespace Microsoft.Net.Http.Server // We need to be able to dispose of the registrations each request to prevent leaks. if (!_disconnectToken.HasValue) { - var connectionDisconnectToken = _server.DisconnectListener.GetTokenForConnection(Request.ConnectionId); + var connectionDisconnectToken = Server.DisconnectListener.GetTokenForConnection(Request.UConnectionId); if (connectionDisconnectToken.CanBeCanceled) { @@ -102,64 +84,29 @@ namespace Microsoft.Net.Http.Server } } - internal WebListener Server - { - get - { - return _server; - } - } - - internal ILogger Logger - { - get { return Server.Logger; } - } - - internal SafeHandle RequestQueueHandle - { - get - { - return _server.RequestQueue.Handle; - } - } - - internal ulong RequestId - { - get - { - return Request.RequestId; - } - } - public unsafe Guid TraceIdentifier { get { // This is the base GUID used by HTTP.SYS for generating the activity ID. // HTTP.SYS overwrites the first 8 bytes of the base GUID with RequestId to generate ETW activity ID. - var guid = new Guid(0xffcb4c93, 0xa57f, 0x453c, 0xb6, 0x3f, 0x84, 0x71, 0xc, 0x79, 0x67, 0xbb); *((ulong*)&guid) = Request.RequestId; return guid; } } - /// - /// The authentication challengest that will be added to the response if the status code is 401. - /// This must be a subset of the AuthenticationSchemes enabled on the server. - /// - public AuthenticationSchemes AuthenticationChallenges { get; set; } - - public bool IsUpgradableRequest - { - get { return _request.IsUpgradable; } - } + public bool IsUpgradableRequest => Request.IsUpgradable; public Task UpgradeAsync() { - if (!IsUpgradableRequest || _response.HasStarted) + if (!IsUpgradableRequest) { - throw new InvalidOperationException("This request cannot be upgraded. It is incompatible, or the response has already started."); + throw new InvalidOperationException("This request cannot be upgraded, it is incompatible."); + } + if (Response.HasStarted) + { + throw new InvalidOperationException("This request cannot be upgraded, the response has already started."); } // Set the status code and reason phrase @@ -176,19 +123,22 @@ namespace Microsoft.Net.Http.Server // TODO: Public when needed internal bool TryGetChannelBinding(ref ChannelBinding value) { - if (!Request.IsSecureConnection) + if (!Request.IsHttps) { LogHelper.LogDebug(Logger, "TryGetChannelBinding", "Channel binding requires HTTPS."); return false; } - value = ClientCertLoader.GetChannelBindingFromTls(Server.RequestQueue, Request.ConnectionId, Logger); + value = ClientCertLoader.GetChannelBindingFromTls(Server.RequestQueue, Request.UConnectionId, Logger); Debug.Assert(value != null, "GetChannelBindingFromTls returned null even though OS supposedly supports Extended Protection"); LogHelper.LogInfo(Logger, "Channel binding retrieved."); return value != null; } + /// + /// Flushes and completes the response. + /// public void Dispose() { if (_disposed) @@ -204,14 +154,17 @@ namespace Microsoft.Net.Http.Server { _requestAbortSource.Dispose(); } - _response.Dispose(); + Response.Dispose(); } finally { - _request.Dispose(); + Request.Dispose(); } } + /// + /// Forcibly terminate and dispose the request, closing the connection if necessary. + /// public void Abort() { // May be called from Dispose() code path, don't check _disposed. @@ -229,8 +182,8 @@ namespace Microsoft.Net.Http.Server } _requestAbortSource.Dispose(); } - ForceCancelRequest(RequestQueueHandle, _request.RequestId); - _request.Dispose(); + ForceCancelRequest(); + Request.Dispose(); } private static void Abort(object state) @@ -239,30 +192,25 @@ namespace Microsoft.Net.Http.Server context.Abort(); } - // This is only called while processing incoming requests. We don't have to worry about canceling - // any response writes. - [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = - "It is safe to ignore the return value on a cancel operation because the connection is being closed")] - internal static void CancelRequest(SafeHandle requestQueueHandle, ulong requestId) + internal CancellationTokenRegistration RegisterForCancellation(CancellationToken cancellationToken) { - UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(requestQueueHandle, requestId, - IntPtr.Zero); + return cancellationToken.Register(AbortDelegate, this); } // The request is being aborted, but large writes may be in progress. Cancel them. - internal void ForceCancelRequest(SafeHandle requestQueueHandle, ulong requestId) + internal void ForceCancelRequest() { try { - uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(requestQueueHandle, requestId, - IntPtr.Zero); + var statusCode = UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(Server.RequestQueue.Handle, + Request.RequestId, IntPtr.Zero); // Either the connection has already dropped, or the last write is in progress. // The requestId becomes invalid as soon as the last Content-Length write starts. // The only way to cancel now is with CancelIoEx. if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID) { - _response.CancelLastWrite(requestQueueHandle); + Response.CancelLastWrite(); } } catch (ObjectDisposedException) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index bfbbf8cb1c..460471838a 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -26,6 +26,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { @@ -48,6 +49,12 @@ namespace Microsoft.Net.Http.Server get { return _requestContext; } } + private SafeHandle RequestQueueHandle => RequestContext.Server.RequestQueue.Handle; + + private ulong RequestId => RequestContext.Request.RequestId; + + private ILogger Logger => RequestContext.Server.Logger; + public override bool CanSeek { get @@ -173,8 +180,8 @@ namespace Microsoft.Net.Http.Server statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, + RequestQueueHandle, + RequestId, flags, (IntPtr)(pBuffer + offset), (uint)size, @@ -186,7 +193,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "Read", exception); + LogHelper.LogException(Logger, "Read", exception); Abort(); throw exception; } @@ -256,8 +263,8 @@ namespace Microsoft.Net.Http.Server statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, + RequestQueueHandle, + RequestId, flags, asyncResult.PinnedBuffer, (uint)size, @@ -266,7 +273,7 @@ namespace Microsoft.Net.Http.Server } catch (Exception e) { - LogHelper.LogException(_requestContext.Logger, "BeginRead", e); + LogHelper.LogException(Logger, "BeginRead", e); asyncResult.Dispose(); throw; } @@ -282,7 +289,7 @@ namespace Microsoft.Net.Http.Server else { Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "BeginRead", exception); + LogHelper.LogException(Logger, "BeginRead", exception); Abort(); throw exception; } @@ -368,7 +375,7 @@ namespace Microsoft.Net.Http.Server var cancellationRegistration = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { - cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); } asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration); @@ -380,8 +387,8 @@ namespace Microsoft.Net.Http.Server statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, + RequestQueueHandle, + RequestId, flags, asyncResult.PinnedBuffer, (uint)size, @@ -392,7 +399,7 @@ namespace Microsoft.Net.Http.Server { asyncResult.Dispose(); Abort(); - LogHelper.LogException(_requestContext.Logger, "ReadAsync", e); + LogHelper.LogException(Logger, "ReadAsync", e); throw; } @@ -409,7 +416,7 @@ namespace Microsoft.Net.Http.Server else { Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "ReadAsync", exception); + LogHelper.LogException(Logger, "ReadAsync", exception); Abort(); throw exception; } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index c7780b6b90..12d7a51bae 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -22,14 +22,12 @@ //------------------------------------------------------------------------------ using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -38,26 +36,26 @@ using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; namespace Microsoft.Net.Http.Server { - public sealed unsafe class Response + public sealed class Response { private ResponseState _responseState; - private HeaderCollection _headers; private string _reasonPhrase; private ResponseStream _nativeStream; + private AuthenticationSchemes _authChallenges; + private TimeSpan? _cacheTtl; private long _expectedBodyLength; private BoundaryType _boundaryType; private HttpApi.HTTP_RESPONSE_V2 _nativeResponse; private IList, object>> _onStartingActions; private IList, object>> _onCompletedActions; - private RequestContext _requestContext; private bool _bufferingEnabled; internal Response(RequestContext requestContext) { // TODO: Verbose log - _requestContext = requestContext; - _headers = new HeaderCollection(); + RequestContext = requestContext; + Headers = new HeaderCollection(); Reset(); } @@ -65,14 +63,13 @@ namespace Microsoft.Net.Http.Server { if (_responseState >= ResponseState.StartedSending) { - _requestContext.Abort(); throw new InvalidOperationException("The response has already been sent. Request Aborted."); } // We haven't started yet, or we're just buffered, we can clear any data, headers, and state so // that we can start over (e.g. to write an error message). _nativeResponse = new HttpApi.HTTP_RESPONSE_V2(); - _headers.IsReadOnly = false; - _headers.Clear(); + Headers.IsReadOnly = false; + Headers.Clear(); _reasonPhrase = null; _boundaryType = BoundaryType.None; _nativeResponse.Response_V1.StatusCode = (ushort)HttpStatusCode.OK; @@ -81,10 +78,11 @@ namespace Microsoft.Net.Http.Server _responseState = ResponseState.Created; _onStartingActions = new List, object>>(); _onCompletedActions = new List, object>>(); - _bufferingEnabled = _requestContext.Server.BufferResponses; + _bufferingEnabled = RequestContext.Server.BufferResponses; _expectedBodyLength = 0; _nativeStream = null; - CacheTtl = null; + _cacheTtl = null; + _authChallenges = RequestContext.Server.AuthenticationManager.AuthenticationSchemes & ~AuthenticationSchemes.AllowAnonymous; } private enum ResponseState @@ -96,30 +94,19 @@ namespace Microsoft.Net.Http.Server Closed, } - private RequestContext RequestContext - { - get - { - return _requestContext; - } - } + private RequestContext RequestContext { get; } - private Request Request - { - get - { - return RequestContext.Request; - } - } + private Request Request => RequestContext.Request; public int StatusCode { get { return _nativeResponse.Response_V1.StatusCode; } set { + // Http.Sys automatically sends 100 Continue responses when you read from the request body. if (value <= 100 || 999 < value) { - throw new ArgumentOutOfRangeException("value", value, string.Format(Resources.Exception_InvalidStatusCode, value)); + throw new ArgumentOutOfRangeException(nameof(value), value, string.Format(Resources.Exception_InvalidStatusCode, value)); } CheckResponseStarted(); _nativeResponse.Response_V1.StatusCode = (ushort)value; @@ -157,26 +144,39 @@ namespace Microsoft.Net.Http.Server } } - internal string GetReasonPhrase(int statusCode) + /// + /// The authentication challenges that will be added to the response if the status code is 401. + /// This must be a subset of the AuthenticationSchemes enabled on the server. + /// + public AuthenticationSchemes AuthenticationChallenges + { + get { return _authChallenges; } + set + { + CheckResponseStarted(); + _authChallenges = value; + } + } + + private string GetReasonPhrase(int statusCode) { string reasonPhrase = ReasonPhrase; if (string.IsNullOrWhiteSpace(reasonPhrase)) { - // if the user hasn't set this, generated on the fly, if possible. - // We know this one is safe, no need to verify it as in the setter. + // If the user hasn't set this then it is generated on the fly if possible. reasonPhrase = HttpReasonPhrase.Get(statusCode) ?? string.Empty; } return reasonPhrase; } // We MUST NOT send message-body when we send responses with these Status codes - private static readonly int[] NoResponseBody = { 100, 101, 204, 205, 304 }; + private static readonly int[] StatusWithNoResponseBody = { 100, 101, 204, 205, 304 }; private static bool CanSendResponseBody(int responseCode) { - for (int i = 0; i < NoResponseBody.Length; i++) + for (int i = 0; i < StatusWithNoResponseBody.Length; i++) { - if (responseCode == NoResponseBody[i]) + if (responseCode == StatusWithNoResponseBody[i]) { return false; } @@ -184,10 +184,7 @@ namespace Microsoft.Net.Http.Server return true; } - public HeaderCollection Headers - { - get { return _headers; } - } + public HeaderCollection Headers { get; } internal long ExpectedBodyLength { @@ -261,6 +258,20 @@ namespace Microsoft.Net.Http.Server } } + /// + /// Enable kernel caching for the response with the given timeout. Http.Sys determines if the response + /// can be cached. + /// + public TimeSpan? CacheTtl + { + get { return _cacheTtl; } + set + { + CheckResponseStarted(); + _cacheTtl = value; + } + } + // should only be called from RequestContext internal void Dispose() { @@ -276,13 +287,17 @@ namespace Microsoft.Net.Http.Server _responseState = ResponseState.Closed; } - // old API, now private, and helper methods - internal BoundaryType BoundaryType { get { return _boundaryType; } } + /// + /// Indicates if the response status, reason, and headers are prepared to send and can + /// no longer be modified. This is caused by the first write to the response body. However, + /// the response may not have been flushed to the network yet if the body is buffered. + /// See HasStartedSending. + /// public bool HasStarted { get { return _responseState >= ResponseState.Started; } @@ -301,13 +316,14 @@ namespace Microsoft.Net.Http.Server get { return _responseState >= ResponseState.ComputedHeaders; } } + /// + /// Indicates the initial response has been flushed to the network and can no longer be modified or Reset. + /// public bool HasStartedSending { get { return _responseState >= ResponseState.StartedSending; } } - public TimeSpan? CacheTtl { get; set; } - private void EnsureResponseStream() { if (_nativeStream == null) @@ -389,11 +405,10 @@ namespace Microsoft.Net.Http.Server } var cachePolicy = new HttpApi.HTTP_CACHE_POLICY(); - var cacheTtl = CacheTtl; - if (cacheTtl.HasValue && cacheTtl.Value > TimeSpan.Zero) + if (_cacheTtl.HasValue && _cacheTtl.Value > TimeSpan.Zero) { cachePolicy.Policy = HttpApi.HTTP_CACHE_POLICY_TYPE.HttpCachePolicyTimeToLive; - cachePolicy.SecondsToLive = (uint)Math.Min(cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue); + cachePolicy.SecondsToLive = (uint)Math.Min(_cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue); } byte[] reasonPhraseBytes = HeaderEncoding.GetBytes(reasonPhrase); @@ -405,7 +420,7 @@ namespace Microsoft.Net.Http.Server { statusCode = HttpApi.HttpSendHttpResponse( - RequestContext.RequestQueueHandle, + RequestContext.Server.RequestQueue.Handle, Request.RequestId, (uint)flags, pResponse, @@ -471,7 +486,7 @@ namespace Microsoft.Net.Http.Server var responseContentLength = ContentLength; var responseCloseSet = Matches(Constants.Close, responseConnectionString); var responseChunkedSet = Matches(Constants.Chunked, transferEncodingString); - var statusCanHaveBody = CanSendResponseBody(_requestContext.Response.StatusCode); + var statusCanHaveBody = CanSendResponseBody(RequestContext.Response.StatusCode); // Determine if the connection will be kept alive or closed. var keepConnectionAlive = true; @@ -540,7 +555,7 @@ namespace Microsoft.Net.Http.Server return string.Equals(knownValue, input?.Trim(), StringComparison.OrdinalIgnoreCase); } - private List SerializeHeaders(bool isOpaqueUpgrade) + private unsafe List SerializeHeaders(bool isOpaqueUpgrade) { Headers.IsReadOnly = true; // Prohibit further modifications. HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; @@ -736,12 +751,9 @@ namespace Microsoft.Net.Http.Server } } - internal void CancelLastWrite(SafeHandle requestQueueHandle) + internal void CancelLastWrite() { - if (_nativeStream != null) - { - _nativeStream.CancelLastWrite(requestQueueHandle); - } + _nativeStream?.CancelLastWrite(); } public Task SendFileAsync(string path, long offset, long? count, CancellationToken cancel) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index fc0919602b..119f87d949 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -29,6 +29,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; namespace Microsoft.Net.Http.Server @@ -56,6 +57,12 @@ namespace Microsoft.Net.Http.Server get { return _requestContext; } } + private SafeHandle RequestQueueHandle => RequestContext.Server.RequestQueue.Handle; + + private ulong RequestId => RequestContext.Request.RequestId; + + private ILogger Logger => RequestContext.Server.Logger; + public override bool CanSeek { get @@ -125,7 +132,7 @@ namespace Microsoft.Net.Http.Server { _requestContext.Abort(); // This is logged rather than thrown because it is too late for an exception to be visible in user code. - LogHelper.LogError(_requestContext.Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length."); + LogHelper.LogError(Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length."); return; } @@ -153,8 +160,8 @@ namespace Microsoft.Net.Http.Server fixed (HttpApi.HTTP_DATA_CHUNK* pDataChunks = dataChunks) { statusCode = HttpApi.HttpSendResponseEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, + RequestQueueHandle, + RequestId, (uint)flags, (ushort)dataChunks.Length, pDataChunks, @@ -182,7 +189,7 @@ namespace Microsoft.Net.Http.Server && (!endOfRequest || (statusCode != ErrorCodes.ERROR_CONNECTION_INVALID && statusCode != ErrorCodes.ERROR_INVALID_PARAMETER))) { Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "Flush", exception); + LogHelper.LogException(Logger, "Flush", exception); Abort(); throw exception; } @@ -287,7 +294,7 @@ namespace Microsoft.Net.Http.Server var cancellationRegistration = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { - cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); } var flags = ComputeLeftToWrite(); @@ -311,8 +318,8 @@ namespace Microsoft.Net.Http.Server else { statusCode = HttpApi.HttpSendResponseEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, + RequestQueueHandle, + RequestId, (uint)flags, asyncResult.DataChunkCount, asyncResult.DataChunks, @@ -325,7 +332,7 @@ namespace Microsoft.Net.Http.Server } catch (Exception e) { - LogHelper.LogException(_requestContext.Logger, "FlushAsync", e); + LogHelper.LogException(Logger, "FlushAsync", e); asyncResult.Dispose(); Abort(); throw; @@ -341,7 +348,7 @@ namespace Microsoft.Net.Http.Server else { Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "FlushAsync", exception); + LogHelper.LogException(Logger, "FlushAsync", exception); Abort(); throw exception; } @@ -408,8 +415,7 @@ namespace Microsoft.Net.Http.Server } if (_leftToWrite == long.MinValue) { - UnsafeNclNativeMethods.HttpApi.HTTP_VERB method = _requestContext.Request.GetKnownMethod(); - if (method == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD) + if (_requestContext.Request.IsHeadMethod) { _leftToWrite = 0; } @@ -578,7 +584,7 @@ namespace Microsoft.Net.Http.Server var cancellationRegistration = default(CancellationTokenRegistration); if (cancellationToken.CanBeCanceled) { - cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext); + cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); } uint statusCode; @@ -615,8 +621,8 @@ namespace Microsoft.Net.Http.Server { // TODO: If opaque then include the buffer data flag. statusCode = HttpApi.HttpSendResponseEntityBody( - _requestContext.RequestQueueHandle, - _requestContext.RequestId, + RequestQueueHandle, + RequestId, (uint)flags, asyncResult.DataChunkCount, asyncResult.DataChunks, @@ -629,7 +635,7 @@ namespace Microsoft.Net.Http.Server } catch (Exception e) { - LogHelper.LogException(_requestContext.Logger, "SendFileAsync", e); + LogHelper.LogException(Logger, "SendFileAsync", e); asyncResult.Dispose(); Abort(); throw; @@ -645,7 +651,7 @@ namespace Microsoft.Net.Http.Server else { Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(_requestContext.Logger, "SendFileAsync", exception); + LogHelper.LogException(Logger, "SendFileAsync", exception); Abort(); throw exception; } @@ -713,12 +719,12 @@ namespace Microsoft.Net.Http.Server // Sync can only be Canceled by CancelSynchronousIo, but we don't attempt this right now. [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = "It is safe to ignore the return value on a cancel operation because the connection is being closed")] - internal unsafe void CancelLastWrite(SafeHandle requestQueueHandle) + internal unsafe void CancelLastWrite() { ResponseStreamAsyncResult asyncState = _lastWrite; if (asyncState != null && !asyncState.IsCompleted) { - UnsafeNclNativeMethods.CancelIoEx(requestQueueHandle, asyncState.NativeOverlapped); + UnsafeNclNativeMethods.CancelIoEx(RequestQueueHandle, asyncState.NativeOverlapped); } } diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index 91eb95af0b..94f3625fc0 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -22,7 +22,6 @@ // ----------------------------------------------------------------------- using System; -using System.Diagnostics; using System.Runtime.InteropServices; namespace Microsoft.Net.Http.Server @@ -53,8 +52,6 @@ namespace Microsoft.Net.Http.Server // // No initialization is required because a value of zero indicates that system defaults should be used. _timeouts = new int[5]; - - LoadConfigurationSettings(); } #region Properties @@ -72,11 +69,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody); + return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody); } set { - SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value); + SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value); } } @@ -95,11 +92,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody); + return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody); } set { - SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value); + SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value); } } @@ -113,11 +110,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue); + return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue); } set { - SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value); + SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value); } } @@ -132,11 +129,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection); + return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection); } set { - SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value); + SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value); } } @@ -152,17 +149,19 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait); + return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait); } set { - SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value); + SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value); } } /// /// The minimum send rate, in bytes-per-second, for the response. The default response send rate is 150 /// bytes-per-second. + /// + /// Use 0 to indicate that system defaults should be used. /// /// To disable this timer set it to UInt32.MaxValue /// @@ -181,60 +180,27 @@ namespace Microsoft.Net.Http.Server throw new ArgumentOutOfRangeException("value"); } - SetServerTimeout(_timeouts, (uint)value); + SetServerTimeouts(_timeouts, (uint)value); _minSendBytesPerSecond = (uint)value; } } #endregion Properties - // Initial values come from the config. The values can then be overridden using this public API. - private void LoadConfigurationSettings() - { - long[] configTimeouts = new long[_timeouts.Length + 1]; // SettingsSectionInternal.Section.HttpListenerTimeouts; - Debug.Assert(configTimeouts != null); - Debug.Assert(configTimeouts.Length == (_timeouts.Length + 1)); - - bool setNonDefaults = false; - for (int i = 0; i < _timeouts.Length; i++) - { - if (configTimeouts[i] != 0) - { - Debug.Assert(configTimeouts[i] <= ushort.MaxValue, "Timeout out of range: " + configTimeouts[i]); - _timeouts[i] = (int)configTimeouts[i]; - setNonDefaults = true; - } - } - - if (configTimeouts[5] != 0) - { - Debug.Assert(configTimeouts[5] <= uint.MaxValue, "Timeout out of range: " + configTimeouts[5]); - _minSendBytesPerSecond = (uint)configTimeouts[5]; - setNonDefaults = true; - } - - if (setNonDefaults) - { - SetServerTimeout(_timeouts, _minSendBytesPerSecond); - } - } - #region Helpers - private TimeSpan GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type) + private TimeSpan GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type) { // Since we maintain local state, GET is local. return new TimeSpan(0, 0, (int)_timeouts[(int)type]); } - private void SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value) + private void SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value) { - Int64 timeoutValue; - // All timeouts are defined as USHORT in native layer (except MinSendRate, which is ULONG). Make sure that // timeout value is within range. - timeoutValue = Convert.ToInt64(value.TotalSeconds); + var timeoutValue = Convert.ToInt64(value.TotalSeconds); if (timeoutValue < 0 || timeoutValue > ushort.MaxValue) { @@ -243,17 +209,15 @@ namespace Microsoft.Net.Http.Server // Use local state to get values for other timeouts. Call into the native layer and if that // call succeeds, update local state. - - int[] currentTimeouts = _timeouts; - currentTimeouts[(int)type] = (int)timeoutValue; - SetServerTimeout(currentTimeouts, _minSendBytesPerSecond); + var newTimeouts = (int[])_timeouts.Clone(); + newTimeouts[(int)type] = (int)timeoutValue; + SetServerTimeouts(newTimeouts, _minSendBytesPerSecond); _timeouts[(int)type] = (int)timeoutValue; } - private unsafe void SetServerTimeout(int[] timeouts, uint minSendBytesPerSecond) + private unsafe void SetServerTimeouts(int[] timeouts, uint minSendBytesPerSecond) { - UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO timeoutinfo = - new UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO(); + var timeoutinfo = new UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO(); timeoutinfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; timeoutinfo.DrainEntityBody = @@ -268,7 +232,7 @@ namespace Microsoft.Net.Http.Server (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait]; timeoutinfo.MinSendRate = minSendBytesPerSecond; - IntPtr infoptr = new IntPtr(&timeoutinfo); + var infoptr = new IntPtr(&timeoutinfo); _server.UrlGroup.SetProperty( UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty, diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 8a7744f269..960373d82e 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -138,17 +138,6 @@ namespace Microsoft.Net.Http.Server get { return _logger; } } - public UrlPrefixCollection UrlPrefixes - { - get { return _urlPrefixes; } - } - - public bool BufferResponses - { - get { return _bufferResponses; } - set { _bufferResponses = value; } - } - internal UrlGroup UrlGroup { get { return _urlGroup; } @@ -164,29 +153,7 @@ namespace Microsoft.Net.Http.Server get { return _disconnectListener; } } - /// - /// Exposes the Http.Sys timeout configurations. These may also be configured in the registry. - /// - public TimeoutManager TimeoutManager - { - get { return _timeoutManager; } - } - - public AuthenticationManager AuthenticationManager - { - get { return _authManager; } - } - - internal static bool IsSupported - { - get { return UnsafeNclNativeMethods.HttpApi.Supported; } - } - - public bool IsListening - { - get { return _state == State.Started; } - } - + // TODO: https://github.com/aspnet/WebListener/issues/173 internal bool IgnoreWriteExceptions { get { return _ignoreWriteExceptions; } @@ -197,6 +164,38 @@ namespace Microsoft.Net.Http.Server } } + public UrlPrefixCollection UrlPrefixes + { + get { return _urlPrefixes; } + } + + public bool BufferResponses + { + get { return _bufferResponses; } + set { _bufferResponses = value; } + } + + /// + /// Exposes the Http.Sys timeout configurations. These may also be configured in the registry. + /// + public TimeoutManager TimeoutManager + { + get { return _timeoutManager; } + } + + /// + /// Http.Sys authentication settings. + /// + public AuthenticationManager AuthenticationManager + { + get { return _authManager; } + } + + public bool IsListening + { + get { return _state == State.Started; } + } + /// /// Sets the maximum number of requests that will be queued up in Http.Sys. /// @@ -208,6 +207,8 @@ namespace Microsoft.Net.Http.Server { throw new ArgumentOutOfRangeException("limit", limit, string.Empty); } + + // Don't try to change it if the new limit is the same if ((!_requestQueueLength.HasValue && limit == DefaultRequestQueueLength) || (_requestQueueLength.HasValue && limit == _requestQueueLength.Value)) { @@ -218,6 +219,9 @@ namespace Microsoft.Net.Http.Server _requestQueue.SetLengthLimit(_requestQueueLength.Value); } + /// + /// Start accepting incoming requests. + /// public void Start() { CheckDisposed(); @@ -298,7 +302,6 @@ namespace Microsoft.Net.Http.Server Dispose(true); } - // old API, now private, and helper methods private void Dispose(bool disposing) { if (!disposing) @@ -350,31 +353,10 @@ namespace Microsoft.Net.Http.Server _serverSession.Dispose(); } - internal unsafe bool ValidateRequest(NativeRequestContext requestMemory) - { - // Block potential DOS attacks - if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit) - { - SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest, authChallenges: null); - return false; - } - return true; - } - - internal unsafe bool ValidateAuth(NativeRequestContext requestMemory) - { - var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob; - if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) - { - SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, - AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationSchemes)); - return false; - } - return true; - } - - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by callback")] - public Task GetContextAsync() + /// + /// Accept a request from the incoming request queue. + /// + public Task AcceptAsync() { AsyncAcceptContext asyncResult = null; try @@ -404,6 +386,29 @@ namespace Microsoft.Net.Http.Server return asyncResult.Task; } + internal unsafe bool ValidateRequest(NativeRequestContext requestMemory) + { + // Block potential DOS attacks + if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit) + { + SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest, authChallenges: null); + return false; + } + return true; + } + + internal unsafe bool ValidateAuth(NativeRequestContext requestMemory) + { + var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob; + if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) + { + SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, + AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationSchemes)); + return false; + } + return true; + } + private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode, IList authChallenges) { UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2(); @@ -494,7 +499,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { // if we fail to send a 401 something's seriously wrong, abort the request - RequestContext.CancelRequest(_requestQueue.Handle, requestId); + UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(_requestQueue.Handle, requestId, IntPtr.Zero); } } finally diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index e8ea925fcf..c79eb2c3f8 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -1,4 +1,8 @@ { + "buildOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 2721e6cab1..3ad4c842ae 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -25,16 +25,16 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); if (authType == AuthenticationSchemes.AllowAnonymous) { - Assert.Equal(AuthenticationSchemes.None, context.AuthenticationChallenges); + Assert.Equal(AuthenticationSchemes.None, context.Response.AuthenticationChallenges); } else { - Assert.Equal(authType, context.AuthenticationChallenges); + Assert.Equal(authType, context.Response.AuthenticationChallenges); } context.Dispose(); @@ -57,7 +57,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var contextTask = server.GetContextAsync(); // Fails when the server shuts down, the challenge happens internally. + var contextTask = server.AcceptAsync(); // Fails when the server shuts down, the challenge happens internally. var response = await responseTask; Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); @@ -77,10 +77,10 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - Assert.Equal(authType, context.AuthenticationChallenges); + Assert.Equal(authType, context.Response.AuthenticationChallenges); context.Response.StatusCode = 401; context.Dispose(); @@ -104,10 +104,10 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - Assert.Equal(authType, context.AuthenticationChallenges); + Assert.Equal(authType, context.Response.AuthenticationChallenges); context.Response.StatusCode = 401; context.Dispose(); @@ -130,17 +130,17 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - Assert.Equal(authType, context.AuthenticationChallenges); + Assert.Equal(authType, context.Response.AuthenticationChallenges); context.Response.StatusCode = 401; context.Dispose(); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); - Assert.Equal(authType, context.AuthenticationChallenges); + Assert.Equal(authType, context.Response.AuthenticationChallenges); context.Dispose(); var response = await responseTask; @@ -161,10 +161,10 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); - Assert.Equal(authType, context.AuthenticationChallenges); + Assert.Equal(authType, context.Response.AuthenticationChallenges); context.Dispose(); var response = await responseTask; @@ -181,10 +181,10 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); - Assert.Equal(AuthenticationSchemes.Kerberos, context.AuthenticationChallenges); + Assert.Equal(AuthenticationSchemes.Kerberos, context.Response.AuthenticationChallenges); context.Dispose(); var response = await responseTask; @@ -201,10 +201,10 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - Assert.Equal(AuthenticationSchemes.Kerberos, context.AuthenticationChallenges); + Assert.Equal(AuthenticationSchemes.Kerberos, context.Response.AuthenticationChallenges); context.Response.StatusCode = 401; context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index 73f915d3b8..ad25c21142 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(Address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); string response = await responseTask; @@ -36,7 +36,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(Address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.ContentLength = body.Length; await context.Response.Body.WriteAsync(body, 0, body.Length); @@ -54,7 +54,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(Address, "Hello World"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); string input = new StreamReader(context.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); context.Response.ContentLength = 11; @@ -75,7 +75,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(Address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var cert = await context.Request.GetClientCertificateAsync(); Assert.Null(cert); context.Dispose(); @@ -94,7 +94,7 @@ namespace Microsoft.Net.Http.Server Assert.NotNull(clientCert); Task responseTask = SendRequestAsync(Address, clientCert); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var cert = await context.Request.GetClientCertificateAsync(); Assert.NotNull(cert); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index d85688e521..274ab452e0 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.Body.Write(body, 0, body.Length); @@ -44,7 +44,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendOpaqueRequestAsync("GET", address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.True(context.IsUpgradableRequest); context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket Stream serverStream = await context.UpgradeAsync(); @@ -88,7 +88,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendOpaqueRequestAsync(method, address, extraHeader); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.True(context.IsUpgradableRequest); context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket Stream serverStream = await context.UpgradeAsync(); @@ -128,7 +128,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServer(out address)) { var clientTask = SendOpaqueRequestAsync(method, address, extraHeader); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.False(context.IsUpgradableRequest); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index d647cd70d9..51229b93bb 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[100]; int read = context.Request.Body.Read(input, 0, input.Length); context.Response.ContentLength = read; @@ -41,7 +41,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[100]; int read = await context.Request.Body.ReadAsync(input, 0, input.Length); context.Response.ContentLength = read; @@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[100]; int read = context.Request.Body.EndRead(context.Request.Body.BeginRead(input, 0, input.Length, null, null)); context.Response.ContentLength = read; @@ -80,7 +80,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[100]; Assert.Throws("buffer", () => context.Request.Body.Read(null, 0, 1)); Assert.Throws("offset", () => context.Request.Body.Read(input, -1, 1)); @@ -105,7 +105,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[10]; int read = context.Request.Body.Read(input, 0, input.Length); Assert.Equal(5, read); @@ -128,7 +128,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[10]; int read = await context.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(5, read); @@ -150,7 +150,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendSocketRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[11]; int read = await context.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(10, read); @@ -176,7 +176,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); @@ -201,7 +201,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); @@ -225,7 +225,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(5)); @@ -250,7 +250,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); @@ -275,7 +275,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); @@ -303,7 +303,7 @@ namespace Microsoft.Net.Http.Server var client = new HttpClient(); var responseTask = client.PostAsync(address, content); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] input = new byte[10]; int read = await context.Request.Body.ReadAsync(input, 0, input.Length, context.DisconnectToken); Assert.False(context.DisconnectToken.IsCancellationRequested); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index 40980cfbd3..c3b1c90caa 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var requestHeaders = context.Request.Headers; // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. // Assert.Equal(2, requestHeaders.Count); @@ -46,7 +46,7 @@ namespace Microsoft.Net.Http.Server string[] customValues = new string[] { "custom1, and custom2", "custom3" }; Task responseTask = SendRequestAsync(address, "Custom-Header", customValues); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var requestHeaders = context.Request.Headers; Assert.Equal(4, requestHeaders.Count); Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); @@ -73,7 +73,7 @@ namespace Microsoft.Net.Http.Server string[] customValues = new string[] { "custom1, and custom测试2", "custom3" }; Task responseTask = SendRequestAsync(address, "Custom-Header", customValues); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var requestHeaders = context.Request.Headers; Assert.Equal(4, requestHeaders.Count); Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index ac7b14d0c6..d69ac9ee81 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(root + "/basepath/SomePath?SomeQuery"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); // General fields var request = context.Request; @@ -64,7 +64,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(root + requestPath); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); // General fields var request = context.Request; @@ -92,7 +92,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) { var responseTask = SendSocketRequestAsync(root, requestPath); - var contextTask = server.GetContextAsync(); + var contextTask = server.AcceptAsync(); var response = await responseTask; var responseStatusCode = response.Substring(9); // Skip "HTTP/1.1 " Assert.Equal("400", responseStatusCode); @@ -106,7 +106,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) { var responseTask = SendSocketRequestAsync(root, "/%252F"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.Equal("/%2F", context.Request.Path); } } @@ -142,7 +142,7 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(root + requestUri); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var request = context.Request; Assert.Equal(expectedPath, request.Path); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 9b990f777c..9a802091f1 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.ShouldBuffer = true; context.Response.Body.Write(new byte[10], 0, 10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); @@ -47,7 +47,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.ShouldBuffer = false; context.Response.Body.Write(new byte[10], 0, 10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); @@ -71,7 +71,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Body.Write(new byte[10], 0, 10); context.Response.Body.Flush(); await context.Response.Body.WriteAsync(new byte[10], 0, 10); @@ -94,7 +94,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["transfeR-Encoding"] = "CHunked"; Stream stream = context.Response.Body; var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); @@ -119,7 +119,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = context.Response.Body; #if NET451 @@ -150,12 +150,12 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); #if !NETCOREAPP1_0 // HttpClient retries the request because it didn't get a response. - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); #endif @@ -171,13 +171,13 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); #if !NETCOREAPP1_0 // HttpClient retries the request because it didn't get a response. - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); @@ -194,14 +194,14 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); #if !NETCOREAPP1_0 // HttpClient retries the request because it didn't get a response. - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); @@ -219,7 +219,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[10], 0, 10); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); @@ -244,7 +244,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Body.Write(new byte[10], 0, 0); Assert.True(context.Response.HasStarted); await context.Response.Body.WriteAsync(new byte[10], 0, 0); @@ -268,7 +268,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.ShouldBuffer = true; for (int i = 0; i < 4; i++) { @@ -299,7 +299,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.ShouldBuffer = true; for (int i = 0; i < 4; i++) { @@ -330,7 +330,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var cts = new CancellationTokenSource(); // First write sends headers await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); @@ -351,7 +351,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(1)); // First write sends headers @@ -373,7 +373,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -395,7 +395,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var cts = new CancellationTokenSource(); // First write sends headers await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 4073056695..f4b5272d41 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -30,7 +30,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -43,7 +43,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -64,7 +64,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -93,7 +93,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -124,7 +124,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.Headers["age"] = "12345"; @@ -156,7 +156,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(0); @@ -169,7 +169,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -190,7 +190,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromMilliseconds(900); @@ -203,7 +203,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -224,7 +224,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(-10); @@ -237,7 +237,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -258,7 +258,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.MaxValue; @@ -285,7 +285,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -315,7 +315,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -329,7 +329,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; context.Dispose(); @@ -348,7 +348,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -363,7 +363,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; context.Dispose(); @@ -382,7 +382,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 10; @@ -411,7 +411,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -425,7 +425,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; context.Dispose(); @@ -444,7 +444,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength =_fileLength; @@ -482,7 +482,7 @@ namespace Microsoft.Net.Http.Server var responseTask = SendRequestAsync(address + status); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.StatusCode = status; context.Response.Headers["x-request-count"] = status.ToString(); context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache @@ -533,7 +533,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, method); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = context.Request.Method + "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -546,7 +546,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address, method); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = context.Request.Method + "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -592,7 +592,7 @@ namespace Microsoft.Net.Http.Server // Cache the first response var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = context.Request.Method + "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -606,7 +606,7 @@ namespace Microsoft.Net.Http.Server // Try to clear the cache with a second request responseTask = SendRequestAsync(address, method); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = context.Request.Method + "2"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Dispose(); @@ -637,7 +637,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "x-vary", "vary1"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.Headers["vary"] = "x-vary"; @@ -668,7 +668,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -681,7 +681,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Dispose(); @@ -702,7 +702,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -715,7 +715,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "2"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Dispose(); @@ -738,7 +738,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "Pragma", "no-cache"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -767,7 +767,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -795,7 +795,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "Cache-Control", "no-cache"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -823,7 +823,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -851,7 +851,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -879,7 +879,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -906,7 +906,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "Range", "bytes=0-10"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.StatusCode = 206; context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache @@ -923,7 +923,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address, "GET", "Range", "bytes=0-10"); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Response.StatusCode = 206; context.Response.Headers["x-request-count"] = "2"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache @@ -951,7 +951,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 100; @@ -981,7 +981,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 100; @@ -1011,7 +1011,7 @@ namespace Microsoft.Net.Http.Server var responseLength = _fileLength / 2; // Make sure it handles partial files. var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = responseLength; @@ -1043,7 +1043,7 @@ namespace Microsoft.Net.Http.Server var responseLength = _fileLength / 2; // Make sure it handles partial files. var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = responseLength; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index a788e2ffb4..0374617f2f 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -44,7 +44,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, usehttp11: false); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -67,7 +67,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendHeadRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -89,7 +89,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendHeadRequestAsync(address, usehttp11: false); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -112,7 +112,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendHeadRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.ContentLength = 20; context.Dispose(); @@ -135,7 +135,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.StatusCode = 204; // No Content context.Dispose(); @@ -158,7 +158,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendHeadRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.StatusCode = 204; // No Content context.Dispose(); @@ -182,7 +182,7 @@ namespace Microsoft.Net.Http.Server WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var responseHeaders = context.Response.Headers; responseHeaders["WWW-Authenticate"] = "custom1"; context.Dispose(); @@ -207,7 +207,7 @@ namespace Microsoft.Net.Http.Server WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var responseHeaders = context.Response.Headers; responseHeaders["WWW-Authenticate"] = new[] { "custom1, and custom2", "custom3" }; context.Dispose(); @@ -236,7 +236,7 @@ namespace Microsoft.Net.Http.Server WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var responseHeaders = context.Response.Headers; responseHeaders["Custom-Header1"] = new[] { "custom1, and custom2", "custom3" }; context.Dispose(); @@ -264,7 +264,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var responseHeaders = context.Response.Headers; responseHeaders["Connection"] = "Close"; context.Dispose(); @@ -284,7 +284,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, usehttp11: false); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -307,7 +307,7 @@ namespace Microsoft.Net.Http.Server request.Version = new Version(1, 0); Task responseTask = client.SendAsync(request); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var responseHeaders = context.Response.Headers; responseHeaders["Transfer-Encoding"] = "chunked"; var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); @@ -335,7 +335,7 @@ namespace Microsoft.Net.Http.Server // Http.Sys does not support 1.0 keep-alives. Task responseTask = SendRequestAsync(address, usehttp11: false, sendKeepAlive: true); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -353,7 +353,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var responseHeaders = context.Response.Headers; responseHeaders["Custom1"] = new[] { "value1a", "value1b" }; @@ -389,7 +389,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var responseHeaders = context.Response.Headers; responseHeaders["Custom1"] = new[] { "value1a", "value1b" }; @@ -443,7 +443,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var responseHeaders = context.Response.Headers; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index 4428dfc086..6ed772dc29 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await Assert.ThrowsAsync(() => context.Response.SendFileAsync("Missing.txt", 0, null, CancellationToken.None)); context.Dispose(); @@ -49,7 +49,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -70,7 +70,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await context.Response.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -91,7 +91,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -112,7 +112,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -134,7 +134,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); context.Dispose(); @@ -155,7 +155,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await Assert.ThrowsAsync( () => context.Response.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None)); context.Dispose(); @@ -172,7 +172,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await Assert.ThrowsAsync( () => context.Response.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None)); context.Dispose(); @@ -189,7 +189,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); context.Dispose(); @@ -214,7 +214,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); await context.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None); Assert.True(context.Response.HasStartedSending); await context.Response.Body.WriteAsync(new byte[10], 0, 10, CancellationToken.None); @@ -238,7 +238,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = FileLength.ToString(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); @@ -260,7 +260,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = "10"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); context.Dispose(); @@ -283,7 +283,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = "0"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs index 4e46f19ef7..12b379c22c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.Equal(200, context.Response.StatusCode); context.Dispose(); @@ -38,7 +38,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.StatusCode = 201; // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value context.Dispose(); @@ -59,7 +59,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.StatusCode = 201; context.Response.ReasonPhrase = "CustomReasonPhrase"; // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value @@ -81,7 +81,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.StatusCode = 901; context.Dispose(); @@ -100,7 +100,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.Throws(() => { context.Response.StatusCode = 100; }); context.Dispose(); @@ -116,7 +116,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.Throws(() => { context.Response.StatusCode = 0; }); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index eebf509011..6b444e4ba6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); var response = await responseTask; @@ -39,7 +39,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Response.ContentLength = 11; using (var writer = new StreamWriter(context.Response.Body)) { @@ -59,7 +59,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); string input = new StreamReader(context.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); context.Response.ContentLength = 11; @@ -86,7 +86,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); @@ -115,7 +115,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); @@ -125,7 +125,7 @@ namespace Microsoft.Net.Http.Server Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); #if !NETCOREAPP1_0 // HttpClient re-tries the request because it doesn't know if the request was received. - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); context.Abort(); #endif await Assert.ThrowsAsync(() => responseTask); @@ -143,7 +143,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); @@ -174,7 +174,7 @@ namespace Microsoft.Net.Http.Server server.SetRequestQueueLimit(1001); var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); context.Dispose(); var response = await responseTask; @@ -190,7 +190,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.Equal(string.Empty, context.Request.PathBase); Assert.Equal("/", context.Request.Path); context.Dispose(); @@ -203,7 +203,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); Assert.Equal("/pathbase", context.Request.PathBase); Assert.Equal("/", context.Request.Path); context.Dispose(); @@ -223,7 +223,7 @@ namespace Microsoft.Net.Http.Server server.UrlPrefixes.Add(address); var responseTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.Equal("/pathbase", context.Request.PathBase); Assert.Equal("/", context.Request.Path); context.Dispose(); @@ -235,7 +235,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.GetContextAsync(); + context = await server.AcceptAsync(); Assert.Equal(string.Empty, context.Request.PathBase); Assert.Equal("/pathbase/", context.Request.Path); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index 6271d2ae93..96bbedaea8 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendRequestAsync(address); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.Body.Write(body, 0, body.Length); @@ -43,7 +43,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.True(context.IsUpgradableRequest); WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); WebSocket clientWebSocket = await clientTask; @@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); - var context = await server.GetContextAsync(); + var context = await server.AcceptAsync(); Assert.True(context.IsWebSocketRequest()); WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); WebSocket clientWebSocket = await clientTask; From 484955f83e99c1776d42b3aea99b6d7672605f60 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 1 Aug 2016 13:23:55 -0700 Subject: [PATCH 365/597] Make MessagePump constructor public for DI --- src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs index 4ba6599e2a..a686dc782e 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs @@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.WebListener private readonly ServerAddressesFeature _serverAddresses; - internal MessagePump(IOptions options, ILoggerFactory loggerFactory) + public MessagePump(IOptions options, ILoggerFactory loggerFactory) { if (options == null) { From 44910bbd590c7a51a9f1bab6c3ff0fdb6fd73ea4 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 3 Aug 2016 09:48:52 -0700 Subject: [PATCH 366/597] Use CoreFx managed WebSockets --- WebListener.sln | 13 - samples/HelloWorld/Program.cs | 2 +- samples/HelloWorld/project.json | 3 +- scripts/UpdateCoreFxCode.ps1 | 44 + .../FeatureContext.cs | 14 +- .../StandardFeatureCollection.cs | 2 - .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestContext.cs | 150 + .../WebSocketHelpers.cs | 193 ++ .../fx/System/Net/WebSockets/CompatHelpers.cs | 49 + .../fx/System/Net/WebSockets/README.md | 5 + .../fx/System/Net/WebSockets/SR.cs | 24 + .../Net/WebSockets/WebSocketValidate.cs | 132 + .../System/Net/WebSockets/ManagedWebSocket.cs | 1312 +++++++++ src/Microsoft.Net.Http.Server/project.json | 8 +- .../HttpKnownHeaderNames.cs | 93 - .../Legacy/SR.cs | 83 - .../WebSocketHttpListenerDuplexStream.cs | 1279 --------- .../Microsoft.Net.WebSockets.Server.xproj | 17 - .../NativeInterop/SafeLoadLibrary.cs | 57 - .../NativeInterop/SafeWebSocketHandle.cs | 48 - .../NativeInterop/UnsafeNativeMethods.cs | 875 ------ .../Properties/AssemblyInfo.cs | 11 - .../ServerWebSocket.cs | 79 - .../WebSocketBase.cs | 2499 ----------------- .../WebSocketBuffer.cs | 711 ----- .../WebSocketConstants.cs | 9 - .../WebSocketError.cs | 39 - .../WebSocketException.cs | 173 -- .../WebSocketExtensions.cs | 217 -- .../WebSocketHelpers.cs | 418 --- .../WebSocketReceiveResultExtensions.cs | 49 - .../SafeHandleZeroOrMinusOneIsInvalid.cs | 48 - .../fx/System/AccessViolationException.cs | 33 - .../fx/System/ExternDll.cs | 33 - .../InteropServices/ExternalException.cs | 115 - .../fx/System/SafeNativeMethods.cs | 44 - .../fx/System/SystemException.cs | 33 - .../project.json | 33 - .../WebSocketTests.cs | 7 +- .../project.json | 3 +- .../WebSocketTests.cs | 2 +- .../project.json | 1 - 43 files changed, 1927 insertions(+), 7035 deletions(-) create mode 100644 scripts/UpdateCoreFxCode.ps1 create mode 100644 src/Microsoft.Net.Http.Server/WebSocketHelpers.cs create mode 100644 src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs create mode 100644 src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/README.md create mode 100644 src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs create mode 100644 src/Microsoft.Net.Http.Server/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs create mode 100644 src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/HttpKnownHeaderNames.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/Legacy/SR.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj delete mode 100644 src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeLoadLibrary.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeWebSocketHandle.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/ServerWebSocket.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketConstants.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketError.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketException.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketExtensions.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketHelpers.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/WebSocketReceiveResultExtensions.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs delete mode 100644 src/Microsoft.Net.WebSockets.Server/project.json diff --git a/WebListener.sln b/WebListener.sln index 52409addaa..5623786165 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -16,8 +16,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\Hello EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.xproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.WebSockets.Server", "src\Microsoft.Net.WebSockets.Server\Microsoft.Net.WebSockets.Server.xproj", "{E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}" -EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.WebListener.FunctionalTests", "test\Microsoft.AspNetCore.Server.WebListener.FunctionalTests\Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj", "{4492FF4C-9032-411D-853F-46B01755E504}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.WebListener", "src\Microsoft.AspNetCore.Server.WebListener\Microsoft.AspNetCore.Server.WebListener.xproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" @@ -83,16 +81,6 @@ Global {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|Mixed Platforms.Build.0 = Release|Any CPU {1236F93A-AC5C-4A77-9477-C88F040151CA}.Release|x86.ActiveCfg = Release|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Debug|x86.ActiveCfg = Debug|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Any CPU.Build.0 = Release|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB}.Release|x86.ActiveCfg = Release|Any CPU {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Any CPU.Build.0 = Debug|Any CPU {4492FF4C-9032-411D-853F-46B01755E504}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -156,7 +144,6 @@ Global {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {1236F93A-AC5C-4A77-9477-C88F040151CA} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {E788AEAE-2CB4-4BFA-8746-D0BB7E93A1BB} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {4492FF4C-9032-411D-853F-46B01755E504} = {E183C826-1360-4DFF-9994-F33CED5C8525} {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1} = {E183C826-1360-4DFF-9994-F33CED5C8525} diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 7e74bf87d0..6ec6112781 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -63,7 +63,7 @@ namespace HelloWorld // Response byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); - if (context.IsWebSocketRequest()) + if (context.IsWebSocketRequest) { Console.WriteLine("WebSocket"); WebSocket webSocket = await context.AcceptWebSocketAsync(); diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 2cd8e62d8f..b63c18564c 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,8 +3,7 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.Net.Http.Server": "0.2.0-*", - "Microsoft.Net.WebSockets.Server": "0.2.0-*" + "Microsoft.Net.Http.Server": "0.2.0-*" }, "commands": { "sample": "HelloWorld" diff --git a/scripts/UpdateCoreFxCode.ps1 b/scripts/UpdateCoreFxCode.ps1 new file mode 100644 index 0000000000..03cd9dfdd5 --- /dev/null +++ b/scripts/UpdateCoreFxCode.ps1 @@ -0,0 +1,44 @@ +param([string]$CoreFxRepoRoot) + +$RepoRoot = Split-Path -Parent $PSScriptRoot + +$FilesToCopy = @( + "src\System.Net.WebSockets.Client\src\System\Net\WebSockets\ManagedWebSocket.cs", + "src\Common\src\System\Net\WebSockets\WebSocketValidate.cs" +) + +if(!$CoreFxRepoRoot) { + $CoreFxRepoRoot = "$RepoRoot\..\..\dotnet\corefx" +} + +if(!(Test-Path $CoreFxRepoRoot)) { + throw "Could not find CoreFx repo at $CoreFxRepoRoot" +} +$CoreFxRepoRoot = Convert-Path $CoreFxRepoRoot + +$DestinationRoot = "$RepoRoot\src\Microsoft.Net.Http.Server\fx\" + +$FilesToCopy | foreach { + $Source = Join-Path $CoreFxRepoRoot $_ + $Destination = Join-Path $DestinationRoot $_ + $DestinationDir = Split-Path -Parent $Destination + + if(!(Test-Path $Source)) { + Write-Warning "Can't find source file: $Source" + } else { + if(!(Test-Path $DestinationDir)) { + mkdir $DestinationDir | Out-Null + } + if(Test-Path $Destination) { + del $Destination + } + Write-Host "Copying $_" + + $SourceCode = [IO.File]::ReadAllText($Source) + $SourceCode = $SourceCode.Replace("Task.FromException", "CompatHelpers.FromException") + $SourceCode = $SourceCode.Replace("Task.CompletedTask", "CompatHelpers.CompletedTask") + $SourceCode = $SourceCode.Replace("Array.Empty", "CompatHelpers.Empty") + $SourceCode = $SourceCode.Replace("nameof(ClientWebSocket)", "`"ClientWebSocket`"") + [IO.File]::WriteAllText($Destination, $SourceCode) + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index 61109f123f..df448e2b72 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -41,9 +41,7 @@ namespace Microsoft.AspNetCore.Server.WebListener ITlsTokenBindingFeature, IHttpBufferingFeature, IHttpRequestLifetimeFeature, -#if WEBSOCKETS IHttpWebSocketFeature, -#endif IHttpAuthenticationFeature, IHttpUpgradeFeature, IHttpRequestIdentifierFeature @@ -436,14 +434,8 @@ namespace Microsoft.AspNetCore.Server.WebListener { return _requestContext.UpgradeAsync(); } -#if WEBSOCKETS - bool IHttpWebSocketFeature.IsWebSocketRequest - { - get - { - return _requestContext.IsWebSocketRequest(); - } - } + + bool IHttpWebSocketFeature.IsWebSocketRequest => _requestContext.IsWebSocketRequest; Task IHttpWebSocketFeature.AcceptAsync(WebSocketAcceptContext context) { @@ -455,7 +447,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } return _requestContext.AcceptWebSocketAsync(subProtocol); } -#endif + ClaimsPrincipal IHttpAuthenticationFeature.User { get diff --git a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs index eccf7418e5..274503edee 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs @@ -38,9 +38,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { typeof(IHttpBufferingFeature), _identityFunc }, { typeof(IHttpRequestLifetimeFeature), _identityFunc }, { typeof(IHttpUpgradeFeature), _identityFunc }, -#if WEBSOCKETS { typeof(IHttpWebSocketFeature), _identityFunc }, -#endif { typeof(IHttpAuthenticationFeature), _identityFunc }, { typeof(IHttpRequestIdentifierFeature), _identityFunc }, { typeof(RequestContext), ctx => ctx.RequestContext }, diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 659ec35310..f812891410 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -207,7 +207,7 @@ namespace Microsoft.Net.Http.Server public HeaderCollection Headers { get; } - private UnsafeNclNativeMethods.HttpApi.HTTP_VERB KnownMethod { get; } + internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB KnownMethod { get; } public bool IsHeadMethod => KnownMethod == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 99c5221a82..6f588fae19 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -24,6 +24,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Net.WebSockets; using System.Security.Authentication.ExtendedProtection; using System.Security.Claims; using System.Threading; @@ -120,6 +121,155 @@ namespace Microsoft.Net.Http.Server return Task.FromResult(opaqueStream); } + // Compare ValidateWebSocketRequest + public bool IsWebSocketRequest + { + get + { + if (!WebSocketHelpers.AreWebSocketsSupported) + { + return false; + } + + if (!IsUpgradableRequest) + { + return false; + } + + if (Request.KnownMethod != UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbGET) + { + return false; + } + + // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) + var connection = Request.Headers[HttpKnownHeaderNames.Connection].ToString(); + if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) + { + return false; + } + + // Upgrade: websocket + var upgrade = Request.Headers[HttpKnownHeaderNames.Upgrade]; + if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // Sec-WebSocket-Version: 13 + var version = Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; + if (!string.Equals(WebSocketHelpers.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // Sec-WebSocket-Key: {base64string} + var key = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + if (!WebSocketHelpers.IsValidWebSocketKey(key)) + { + return false; + } + + return true; + } + } + + // Compare IsWebSocketRequest() + private void ValidateWebSocketRequest() + { + if (!WebSocketHelpers.AreWebSocketsSupported) + { + throw new NotSupportedException("WebSockets are not supported on this platform."); + } + + if (!IsUpgradableRequest) + { + throw new InvalidOperationException("This request is not a valid upgrade request."); + } + + if (Request.KnownMethod != UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbGET) + { + throw new InvalidOperationException("This request is not a valid upgrade request; invalid verb: " + Request.Method); + } + + // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) + var connection = Request.Headers[HttpKnownHeaderNames.Connection].ToString(); + if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) + { + throw new InvalidOperationException("The Connection header is invalid: " + connection); + } + + // Upgrade: websocket + var upgrade = Request.Headers[HttpKnownHeaderNames.Upgrade]; + if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The Upgrade header is invalid: " + upgrade); + } + + // Sec-WebSocket-Version: 13 + var version = Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; + if (!string.Equals(WebSocketHelpers.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The Sec-WebSocket-Version header is invalid or not supported: " + version); + } + + // Sec-WebSocket-Key: {base64string} + var key = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + if (!WebSocketHelpers.IsValidWebSocketKey(key)) + { + throw new InvalidOperationException("The Sec-WebSocket-Key header is invalid: " + upgrade); + } + } + + public Task AcceptWebSocketAsync() + { + return AcceptWebSocketAsync(null, WebSocketHelpers.DefaultReceiveBufferSize, WebSocketHelpers.DefaultKeepAliveInterval); + } + + public Task AcceptWebSocketAsync(string subProtocol) + { + return AcceptWebSocketAsync(subProtocol, WebSocketHelpers.DefaultReceiveBufferSize, WebSocketHelpers.DefaultKeepAliveInterval); + } + + public Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval) + { + return AcceptWebSocketAsync(subProtocol, WebSocketHelpers.DefaultReceiveBufferSize, keepAliveInterval); + } + + public Task AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval) + { + if (!IsUpgradableRequest) + { + throw new InvalidOperationException("This request is cannot be upgraded."); + } + WebSocketHelpers.ValidateOptions(subProtocol, keepAliveInterval); + + return AcceptWebSocketAsyncCore(subProtocol, receiveBufferSize, keepAliveInterval); + } + + private async Task AcceptWebSocketAsyncCore(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval) + { + ValidateWebSocketRequest(); + + var subProtocols = Request.Headers.GetValues(HttpKnownHeaderNames.SecWebSocketProtocol); + var shouldSendSecWebSocketProtocolHeader = WebSocketHelpers.ProcessWebSocketProtocolHeader(subProtocols, subProtocol); + if (shouldSendSecWebSocketProtocolHeader) + { + Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = subProtocol; + } + + // negotiate the websocket key return value + var secWebSocketKey = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; + var secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); + + Response.Headers.Append(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); + Response.Headers.Append(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); + Response.Headers.Append(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); + + var opaqueStream = await UpgradeAsync(); + + return WebSocketHelpers.CreateServerWebSocket(opaqueStream, subProtocol, receiveBufferSize, keepAliveInterval); + } + // TODO: Public when needed internal bool TryGetChannelBinding(ref ChannelBinding value) { diff --git a/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs b/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs new file mode 100644 index 0000000000..6d4822ab3e --- /dev/null +++ b/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs @@ -0,0 +1,193 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net.WebSockets; +using System.Security.Cryptography; +using System.Text; +using System.Threading; + +namespace Microsoft.Net.Http.Server +{ + internal static class WebSocketHelpers + { + internal static string SupportedProtocolVersion = "13"; + + internal const string SecWebSocketKeyGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + internal const string WebSocketUpgradeToken = "websocket"; + internal const int DefaultReceiveBufferSize = 16 * 1024; + internal const int DefaultClientSendBufferSize = 16 * 1024; + internal const int MaxControlFramePayloadLength = 123; + internal static readonly TimeSpan DefaultKeepAliveInterval = TimeSpan.FromMinutes(2); + + // RFC 6455 requests WebSocket clients to let the server initiate the TCP close to avoid that client sockets + // end up in TIME_WAIT-state + // + // After both sending and receiving a Close message, an endpoint considers the WebSocket connection closed and + // MUST close the underlying TCP connection. The server MUST close the underlying TCP connection immediately; + // the client SHOULD wait for the server to close the connection but MAY close the connection at any time after + // sending and receiving a Close message, e.g., if it has not received a TCP Close from the server in a + // reasonable time period. + internal const int ClientTcpCloseTimeout = 1000; // 1s + + private const int CloseStatusCodeAbort = 1006; + private const int CloseStatusCodeFailedTLSHandshake = 1015; + private const int InvalidCloseStatusCodesFrom = 0; + private const int InvalidCloseStatusCodesTo = 999; + private const string Separators = "()<>@,;:\\\"/[]?={} "; + + internal static readonly ArraySegment EmptyPayload = new ArraySegment(new byte[] { }, 0, 0); + private static readonly Random KeyGenerator = new Random(); + + internal static bool AreWebSocketsSupported + { + get + { + // https://github.com/aspnet/WebListener/issues/215 + return true; // TODO: ComNetOS.IsWin8orLater; + } + } + + internal static bool IsValidWebSocketKey(string key) + { + if (string.IsNullOrWhiteSpace(key)) + { + return false; + } + // TODO: + // throw new NotImplementedException(); + return true; + } + + internal static string GetSecWebSocketAcceptString(string secWebSocketKey) + { + string retVal; + // SHA1 used only for hashing purposes, not for crypto. Check here for FIPS compat. + using (SHA1 sha1 = SHA1.Create()) + { + string acceptString = string.Concat(secWebSocketKey, WebSocketHelpers.SecWebSocketKeyGuid); + byte[] toHash = Encoding.UTF8.GetBytes(acceptString); + retVal = Convert.ToBase64String(sha1.ComputeHash(toHash)); + } + return retVal; + } + + internal static WebSocket CreateServerWebSocket(Stream opaqueStream, string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval) + { + return ManagedWebSocket.CreateFromConnectedStream(opaqueStream, isServer: true, subprotocol: subProtocol, + keepAliveIntervalSeconds: (int)keepAliveInterval.TotalSeconds, receiveBufferSize: receiveBufferSize); + } + + // return value here signifies if a Sec-WebSocket-Protocol header should be returned by the server. + internal static bool ProcessWebSocketProtocolHeader(IEnumerable clientSecWebSocketProtocols, string subProtocol) + { + if (clientSecWebSocketProtocols == null || !clientSecWebSocketProtocols.Any()) + { + // client hasn't specified any Sec-WebSocket-Protocol header + if (!string.IsNullOrEmpty(subProtocol)) + { + // If the server specified _anything_ this isn't valid. + throw new WebSocketException(WebSocketError.UnsupportedProtocol, + "The client did not specify a Sec-WebSocket-Protocol header. SubProtocol: " + subProtocol); + } + // Treat empty and null from the server as the same thing here, server should not send headers. + return false; + } + + // here, we know the client specified something and it's non-empty. + + if (string.IsNullOrEmpty(subProtocol)) + { + // client specified some protocols, server specified 'null'. So server should send headers. + return false; + } + + // here, we know that the client has specified something, it's not empty + // and the server has specified exactly one protocol + + // client specified protocols, serverOptions has exactly 1 non-empty entry. Check that + // this exists in the list the client specified. + foreach (var currentRequestProtocol in clientSecWebSocketProtocols) + { + if (string.Compare(subProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase) == 0) + { + return true; + } + } + + throw new WebSocketException(WebSocketError.UnsupportedProtocol, + $"Unsupported protocol: {subProtocol}; Client supported protocols: {string.Join(", ", clientSecWebSocketProtocols)}"); + } + + internal static void ValidateSubprotocol(string subProtocol) + { + if (string.IsNullOrEmpty(subProtocol)) + { + return; + } + + char[] chars = subProtocol.ToCharArray(); + string invalidChar = null; + int i = 0; + while (i < chars.Length) + { + char ch = chars[i]; + if (ch < 0x21 || ch > 0x7e) + { + invalidChar = string.Format(CultureInfo.InvariantCulture, "[{0}]", (int)ch); + break; + } + + if (!char.IsLetterOrDigit(ch) && + Separators.IndexOf(ch) >= 0) + { + invalidChar = ch.ToString(); + break; + } + + i++; + } + + if (invalidChar != null) + { + throw new ArgumentException($"Invalid character '{invalidChar}' in the subProtocol '{subProtocol}'", nameof(subProtocol)); + } + } + + internal static void ValidateOptions(string subProtocol, TimeSpan keepAliveInterval) + { + ValidateSubprotocol(subProtocol); + + // -1 + if (keepAliveInterval < Timeout.InfiniteTimeSpan) + { + throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), keepAliveInterval, + "The value must be greater than or equal too 0 seconds, or -1 second to disable."); + } + } + } +} diff --git a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs new file mode 100644 index 0000000000..9bb3fa57fe --- /dev/null +++ b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; + +namespace System.Net.WebSockets +{ + // Needed to support the WebSockets code from CoreFX. + internal static class CompatHelpers + { + internal static readonly Task CompletedTask; + + static CompatHelpers() + { + var tcs = new TaskCompletionSource(); + tcs.SetResult(null); + CompletedTask = tcs.Task; + } + + public static Task FromException(Exception ex) + { +#if NET451 + return FromException(ex); +#else + return Task.FromException(ex); +#endif + } + + public static Task FromException(Exception ex) + { +#if NET451 + var tcs = new TaskCompletionSource(); + tcs.SetException(ex); + return tcs.Task; +#else + return Task.FromException(ex); +#endif + } + + internal static T[] Empty() + { +#if NET451 + return new T[0]; +#else + return Array.Empty(); +#endif + } + } + + // This is just here to be used by a nameof in the CoreFX code. + //internal static class ClientWebSocket { } +} \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/README.md b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/README.md new file mode 100644 index 0000000000..4b8f84b7ed --- /dev/null +++ b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/README.md @@ -0,0 +1,5 @@ +# External Code + +External code copied from CoreFX. Do not modify files in this directory, use the `scripts\UpdateCoreFxCore.ps1` script in the repo root. + +This folder structure is designed to exactly mirror the structure in the CoreFX repo (hence the deep nesting). \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs new file mode 100644 index 0000000000..8753b1c60e --- /dev/null +++ b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace System.Net.WebSockets +{ + // Needed to support the WebSockets code from CoreFX. + internal static class SR + { + internal static readonly string net_Websockets_AlreadyOneOutstandingOperation = nameof(net_Websockets_AlreadyOneOutstandingOperation); + internal static readonly string net_WebSockets_Argument_InvalidMessageType = nameof(net_WebSockets_Argument_InvalidMessageType); + internal static readonly string net_WebSockets_InvalidCharInProtocolString = nameof(net_WebSockets_InvalidCharInProtocolString); + internal static readonly string net_WebSockets_InvalidCloseStatusCode = nameof(net_WebSockets_InvalidCloseStatusCode); + internal static readonly string net_WebSockets_InvalidCloseStatusDescription = nameof(net_WebSockets_InvalidCloseStatusDescription); + internal static readonly string net_WebSockets_InvalidEmptySubProtocol = nameof(net_WebSockets_InvalidEmptySubProtocol); + internal static readonly string net_WebSockets_InvalidState = nameof(net_WebSockets_InvalidState); + internal static readonly string net_WebSockets_InvalidState_ClosedOrAborted = nameof(net_WebSockets_InvalidState_ClosedOrAborted); + internal static readonly string net_WebSockets_ReasonNotNull = nameof(net_WebSockets_ReasonNotNull); + internal static readonly string net_WebSockets_UnsupportedPlatform = nameof(net_WebSockets_UnsupportedPlatform); + + internal static string Format(string name, params object[] args) => $"TODO, RESX: {name}; ({string.Join(",", args)})"; + } +} \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs b/src/Microsoft.Net.Http.Server/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs new file mode 100644 index 0000000000..06e07f29dd --- /dev/null +++ b/src/Microsoft.Net.Http.Server/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs @@ -0,0 +1,132 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Globalization; +using System.Text; + +namespace System.Net.WebSockets +{ + internal static class WebSocketValidate + { + internal const int MaxControlFramePayloadLength = 123; + private const int CloseStatusCodeAbort = 1006; + private const int CloseStatusCodeFailedTLSHandshake = 1015; + private const int InvalidCloseStatusCodesFrom = 0; + private const int InvalidCloseStatusCodesTo = 999; + private const string Separators = "()<>@,;:\\\"/[]?={} "; + + internal static void ValidateSubprotocol(string subProtocol) + { + if (string.IsNullOrWhiteSpace(subProtocol)) + { + throw new ArgumentException(SR.net_WebSockets_InvalidEmptySubProtocol, nameof(subProtocol)); + } + + string invalidChar = null; + int i = 0; + while (i < subProtocol.Length) + { + char ch = subProtocol[i]; + if (ch < 0x21 || ch > 0x7e) + { + invalidChar = string.Format(CultureInfo.InvariantCulture, "[{0}]", (int)ch); + break; + } + + if (!char.IsLetterOrDigit(ch) && + Separators.IndexOf(ch) >= 0) + { + invalidChar = ch.ToString(); + break; + } + + i++; + } + + if (invalidChar != null) + { + throw new ArgumentException(SR.Format(SR.net_WebSockets_InvalidCharInProtocolString, subProtocol, invalidChar), nameof(subProtocol)); + } + } + + internal static void ValidateCloseStatus(WebSocketCloseStatus closeStatus, string statusDescription) + { + if (closeStatus == WebSocketCloseStatus.Empty && !string.IsNullOrEmpty(statusDescription)) + { + throw new ArgumentException(SR.Format(SR.net_WebSockets_ReasonNotNull, + statusDescription, + WebSocketCloseStatus.Empty), + nameof(statusDescription)); + } + + int closeStatusCode = (int)closeStatus; + + if ((closeStatusCode >= InvalidCloseStatusCodesFrom && + closeStatusCode <= InvalidCloseStatusCodesTo) || + closeStatusCode == CloseStatusCodeAbort || + closeStatusCode == CloseStatusCodeFailedTLSHandshake) + { + // CloseStatus 1006 means Aborted - this will never appear on the wire and is reflected by calling WebSocket.Abort + throw new ArgumentException(SR.Format(SR.net_WebSockets_InvalidCloseStatusCode, + closeStatusCode), + nameof(closeStatus)); + } + + int length = 0; + if (!string.IsNullOrEmpty(statusDescription)) + { + length = Encoding.UTF8.GetByteCount(statusDescription); + } + + if (length > MaxControlFramePayloadLength) + { + throw new ArgumentException(SR.Format(SR.net_WebSockets_InvalidCloseStatusDescription, + statusDescription, + MaxControlFramePayloadLength), + nameof(statusDescription)); + } + } + + internal static void ThrowPlatformNotSupportedException() + { + throw new PlatformNotSupportedException(SR.net_WebSockets_UnsupportedPlatform); + } + + internal static void ValidateArraySegment(ArraySegment arraySegment, string parameterName) + { + if (arraySegment.Array == null) + { + throw new ArgumentNullException(parameterName + ".Array"); + } + } + + internal static void ThrowIfInvalidState(WebSocketState currentState, bool isDisposed, WebSocketState[] validStates) + { + string validStatesText = string.Empty; + + if (validStates != null && validStates.Length > 0) + { + foreach (WebSocketState validState in validStates) + { + if (currentState == validState) + { + // Ordering is important to maintain .NET 4.5 WebSocket implementation exception behavior. + if (isDisposed) + { + throw new ObjectDisposedException("ClientWebSocket"); + } + + return; + } + } + + validStatesText = string.Join(", ", validStates); + } + + throw new WebSocketException( + WebSocketError.InvalidState, + SR.Format(SR.net_WebSockets_InvalidState, currentState, validStatesText)); + } + } +} diff --git a/src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs new file mode 100644 index 0000000000..738b0a7348 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs @@ -0,0 +1,1312 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +// NOTE: This file is shared between CoreFX and ASP.NET. Be very thoughtful when changing it. + +namespace System.Net.WebSockets +{ + /// A managed implementation of a web socket that sends and receives data via a . + /// + /// Thread-safety: + /// - It's acceptable to call ReceiveAsync and SendAsync in parallel. One of each may run concurrently. + /// - It's acceptable to have a pending ReceiveAsync while CloseOutputAsync or CloseAsync is called. + /// - Attemping to invoke any other operations in parallel may corrupt the instance. Attempting to invoke + /// a send operation while another is in progress or a receive operation while another is in progress will + /// result in an exception. + /// + internal sealed class ManagedWebSocket : WebSocket + { + /// Creates a from a connected to a websocket endpoint. + /// The connected Stream. + /// true if this is the server-side of the connection; false if this is the client-side of the connection. + /// The agreed upon subprotocol for the connection. + /// The current state of the websocket connection. + /// The interval to use for keep-alive pings. + /// The buffer size to use for received data. + /// The created instance. + public static ManagedWebSocket CreateFromConnectedStream( + Stream stream, bool isServer, string subprotocol, + int keepAliveIntervalSeconds = 30, int receiveBufferSize = 0x1000) + { + return new ManagedWebSocket(stream, isServer, subprotocol, TimeSpan.FromSeconds(keepAliveIntervalSeconds), receiveBufferSize); + } + + /// Per-thread cached 4-byte mask byte array. + [ThreadStatic] + private static byte[] t_headerMask; + + /// Thread-safe random number generator used to generate masks for each send. + private static readonly RandomNumberGenerator s_random = RandomNumberGenerator.Create(); + /// Encoding for the payload of text messages: UTF8 encoding that throws if invalid bytes are discovered, per the RFC. + private static readonly UTF8Encoding s_textEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); + + /// Valid states to be in when calling SendAsync. + private static readonly WebSocketState[] s_validSendStates = { WebSocketState.Open, WebSocketState.CloseReceived }; + /// Valid states to be in when calling ReceiveAsync. + private static readonly WebSocketState[] s_validReceiveStates = { WebSocketState.Open, WebSocketState.CloseSent }; + /// Valid states to be in when calling CloseOutputAsync. + private static readonly WebSocketState[] s_validCloseOutputStates = { WebSocketState.Open, WebSocketState.CloseReceived }; + /// Valid states to be in when calling CloseAsync. + private static readonly WebSocketState[] s_validCloseStates = { WebSocketState.Open, WebSocketState.CloseReceived, WebSocketState.CloseSent }; + + /// The maximum size in bytes of a message frame header that includes mask bytes. + private const int MaxMessageHeaderLength = 14; + /// The maximum size of a control message payload. + private const int MaxControlPayloadLength = 125; + /// Length of the mask XOR'd with the payload data. + private const int MaskLength = 4; + + /// The stream used to communicate with the remote server. + private readonly Stream _stream; + /// + /// true if this is the server-side of the connection; false if it's client. + /// This impacts masking behavior: clients always mask payloads they send and + /// expect to always receive unmasked payloads, whereas servers always send + /// unmasked payloads and expect to always receive masked payloads. + /// + private readonly bool _isServer = false; + /// The agreed upon subprotocol with the server. + private readonly string _subprotocol; + /// Timer used to send periodic pings to the server, at the interval specified + private readonly Timer _keepAliveTimer; + /// CancellationTokenSource used to abort all current and future operations when anything is canceled or any error occurs. + private readonly CancellationTokenSource _abortSource = new CancellationTokenSource(); + /// Buffer used for reading data from the network. + private readonly byte[] _receiveBuffer; + /// + /// Tracks the state of the validity of the UTF8 encoding of text payloads. Text may be split across fragments. + /// + private readonly Utf8MessageState _utf8TextState = new Utf8MessageState(); + /// + /// Semaphore used to ensure that calls to SendFrameAsync don't run concurrently. While + /// is used to fail if a caller tries to issue another SendAsync while a previous one is running, internally + /// we use SendFrameAsync as an implementation detail, and it should not cause user requests to SendAsync to fail, + /// nor should such internal usage be allowed to run concurrently with other internal usage or with SendAsync. + /// + private readonly SemaphoreSlim _sendFrameAsyncLock = new SemaphoreSlim(1, 1); + + // We maintain the current WebSocketState in _state. However, we separately maintain _sentCloseFrame and _receivedCloseFrame + // as there isn't a strict ordering between CloseSent and CloseReceived. If we receive a close frame from the server, we need to + // transition to CloseReceived even if we're currently in CloseSent, and if we send a close frame, we need to transition to + // CloseSent even if we're currently in CloseReceived. + + /// The current state of the web socket in the protocol. + private WebSocketState _state = WebSocketState.Open; + /// true if Dispose has been called; otherwise, false. + private bool _disposed; + /// Whether we've ever sent a close frame. + private bool _sentCloseFrame; + /// Whether we've ever received a close frame. + private bool _receivedCloseFrame; + /// The reason for the close, as sent by the server, or null if not yet closed. + private WebSocketCloseStatus? _closeStatus = null; + /// A description of the close reason as sent by the server, or null if not yet closed. + private string _closeStatusDescription = null; + + /// + /// The last header received in a ReceiveAsync. If ReceiveAsync got a header but then + /// returned fewer bytes than was indicated in the header, subsequent ReceiveAsync calls + /// will use the data from the header to construct the subsequent receive results, and + /// the payload length in this header will be decremented to indicate the number of bytes + /// remaining to be received for that header. As a result, between fragments, the payload + /// length in this header should be 0. + /// + private MessageHeader _lastReceiveHeader = new MessageHeader { Opcode = MessageOpcode.Text, Fin = true }; + /// The offset of the next available byte in the _receiveBuffer. + private int _receiveBufferOffset = 0; + /// The number of bytes available in the _receiveBuffer. + private int _receiveBufferCount = 0; + /// + /// When dealing with partially read fragments of binary/text messages, a mask previously received may still + /// apply, and the first new byte received may not correspond to the 0th position in the mask. This value is + /// the next offset into the mask that should be applied. + /// + private int _receivedMaskOffsetOffset = 0; + /// + /// Buffer used to store the complete message to be sent to the stream. This is needed + /// rather than just sending a header and then the user's buffer, as we need to mutate the + /// buffered data with the mask, and we don't want to change the data in the user's buffer. + /// + private byte[] _sendBuffer; + /// + /// Whether the last SendAsync had endOfMessage==false. We need to track this so that we + /// can send the subsequent message with a continuation opcode if the last message was a fragment. + /// + private bool _lastSendWasFragment; + /// + /// The task returned from the last SendAsync operation to not complete synchronously. + /// If this is not null and not completed when a subsequent SendAsync is issued, an exception occurs. + /// + private Task _lastSendAsync; + /// + /// The task returned from the last ReceiveAsync operation to not complete synchronously. + /// If this is not null and not completed when a subsequent ReceiveAsync is issued, an exception occurs. + /// + private Task _lastReceiveAsync; + + /// Lock used to protect update and check-and-update operations on _state. + private object StateUpdateLock => _abortSource; + /// + /// We need to coordinate between receives and close operations happening concurrently, as a ReceiveAsync may + /// be pending while a Close{Output}Async is issued, which itself needs to loop until a close frame is received. + /// As such, we need thread-safety in the management of . + /// + private object ReceiveAsyncLock => _utf8TextState; // some object, as we're simply lock'ing on it + + /// Initializes the websocket. + /// The connected Stream. + /// true if this is the server-side of the connection; false if this is the client-side of the connection. + /// The agreed upon subprotocol for the connection. + /// The interval to use for keep-alive pings. + /// The buffer size to use for received data. + private ManagedWebSocket(Stream stream, bool isServer, string subprotocol, TimeSpan keepAliveInterval, int receiveBufferSize) + { + Debug.Assert(StateUpdateLock != null, $"Expected {nameof(StateUpdateLock)} to be non-null"); + Debug.Assert(ReceiveAsyncLock != null, $"Expected {nameof(ReceiveAsyncLock)} to be non-null"); + Debug.Assert(StateUpdateLock != ReceiveAsyncLock, "Locks should be different objects"); + + Debug.Assert(stream != null, $"Expected non-null stream"); + Debug.Assert(stream.CanRead, $"Expected readable stream"); + Debug.Assert(stream.CanWrite, $"Expected writeable stream"); + Debug.Assert(keepAliveInterval == Timeout.InfiniteTimeSpan || keepAliveInterval >= TimeSpan.Zero, $"Invalid keepalive interval: {keepAliveInterval}"); + Debug.Assert(receiveBufferSize >= MaxMessageHeaderLength, $"Receive buffer size {receiveBufferSize} is too small"); + + _stream = stream; + _isServer = isServer; + _subprotocol = subprotocol; + _receiveBuffer = new byte[Math.Max(receiveBufferSize, MaxMessageHeaderLength)]; + + // Set up the abort source so that if it's triggered, we transition the instance appropriately. + _abortSource.Token.Register(s => + { + var thisRef = (ManagedWebSocket)s; + + lock (thisRef.StateUpdateLock) + { + WebSocketState state = thisRef._state; + if (state != WebSocketState.Closed && state != WebSocketState.Aborted) + { + thisRef._state = state != WebSocketState.None && state != WebSocketState.Connecting ? + WebSocketState.Aborted : + WebSocketState.Closed; + } + } + }, this); + + // Now that we're opened, initiate the keep alive timer to send periodic pings + if (keepAliveInterval > TimeSpan.Zero) + { + _keepAliveTimer = new Timer(s => ((ManagedWebSocket)s).SendKeepAliveFrameAsync(), this, keepAliveInterval, keepAliveInterval); + } + } + + public override void Dispose() + { + lock (StateUpdateLock) + { + DisposeCore(); + } + } + + private void DisposeCore() + { + Debug.Assert(Monitor.IsEntered(StateUpdateLock), $"Expected {nameof(StateUpdateLock)} to be held"); + if (!_disposed) + { + _disposed = true; + _keepAliveTimer?.Dispose(); + _stream?.Dispose(); + if (_state < WebSocketState.Aborted) + { + _state = WebSocketState.Closed; + } + } + } + + public override WebSocketCloseStatus? CloseStatus => _closeStatus; + + public override string CloseStatusDescription => _closeStatusDescription; + + public override WebSocketState State => _state; + + public override string SubProtocol => _subprotocol; + + public override Task SendAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) + { + if (messageType != WebSocketMessageType.Text && messageType != WebSocketMessageType.Binary) + { + throw new ArgumentException(SR.Format( + SR.net_WebSockets_Argument_InvalidMessageType, + nameof(WebSocketMessageType.Close), nameof(SendAsync), nameof(WebSocketMessageType.Binary), nameof(WebSocketMessageType.Text), nameof(CloseOutputAsync)), + nameof(messageType)); + } + WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer)); + + try + { + WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validSendStates); + ThrowIfOperationInProgress(_lastSendAsync); + } + catch (Exception exc) + { + return CompatHelpers.FromException(exc); + } + + MessageOpcode opcode = + _lastSendWasFragment ? MessageOpcode.Continuation : + messageType == WebSocketMessageType.Binary ? MessageOpcode.Binary : + MessageOpcode.Text; + + Task t = SendFrameAsync(opcode, endOfMessage, buffer, cancellationToken); + _lastSendWasFragment = !endOfMessage; + _lastSendAsync = t; + return t; + } + + public override Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) + { + WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer)); + + try + { + WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validReceiveStates); + + Debug.Assert(!Monitor.IsEntered(StateUpdateLock), $"{nameof(StateUpdateLock)} must never be held when acquiring {nameof(ReceiveAsyncLock)}"); + lock (ReceiveAsyncLock) // synchronize with receives in CloseAsync + { + ThrowIfOperationInProgress(_lastReceiveAsync); + Task t = ReceiveAsyncPrivate(buffer, cancellationToken); + _lastReceiveAsync = t; + return t; + } + } + catch (Exception exc) + { + return CompatHelpers.FromException(exc); + } + } + + public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) + { + WebSocketValidate.ValidateCloseStatus(closeStatus, statusDescription); + + try + { + WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validCloseStates); + } + catch (Exception exc) + { + return CompatHelpers.FromException(exc); + } + + return CloseAsyncPrivate(closeStatus, statusDescription, cancellationToken); + } + + public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) + { + WebSocketValidate.ValidateCloseStatus(closeStatus, statusDescription); + + try + { + WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validCloseOutputStates); + } + catch (Exception exc) + { + return CompatHelpers.FromException(exc); + } + + return SendCloseFrameAsync(closeStatus, statusDescription, cancellationToken); + } + + public override void Abort() + { + _abortSource.Cancel(); + Dispose(); // forcibly tear down connection + } + + /// Sends a websocket frame to the network. + /// The opcode for the message. + /// The value of the FIN bit for the message. + /// The buffer containing the payload data fro the message. + /// The CancellationToken to use to cancel the websocket. + private Task SendFrameAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment payloadBuffer, CancellationToken cancellationToken) + { + // TODO: #4900 SendFrameAsync should in theory typically complete synchronously, making it fast and allocation free. + // However, due to #4900, it almost always yields, resulting in all of the allocations involved in an async method + // yielding, e.g. the boxed state machine, the Action delegate, the MoveNextRunner, and the resulting Task, plus it's + // common that the awaited operation completes so fast after the await that we may end up allocating an AwaitTaskContinuation + // inside of the TaskAwaiter. Since SendFrameAsync is such a core code path, until that can be fixed, we put some + // optimizations in place to avoid a few of those expenses, at the expense of more complicated code; for the common case, + // this code has fewer than half the number and size of allocations. If/when that issue is fixed, this method should be deleted + // and replaced by SendFrameFallbackAsync, which is the same logic but in a much more easily understand flow. + + // If a cancelable cancellation token was provided, that would require registering with it, which means more state we have to + // pass around (the CancellationTokenRegistration), so if it is cancelable, just immediately go to the fallback path. + // Similarly, it should be rare that there are multiple outstanding calls to SendFrameAsync, but if there are, again + // fall back to the fallback path. + return cancellationToken.CanBeCanceled || !_sendFrameAsyncLock.Wait(0) ? + SendFrameFallbackAsync(opcode, endOfMessage, payloadBuffer, cancellationToken) : + SendFrameLockAcquiredNonCancelableAsync(opcode, endOfMessage, payloadBuffer); + } + + /// Sends a websocket frame to the network. The caller must hold the sending lock. + /// The opcode for the message. + /// The value of the FIN bit for the message. + /// The buffer containing the payload data fro the message. + private Task SendFrameLockAcquiredNonCancelableAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment payloadBuffer) + { + Debug.Assert(_sendFrameAsyncLock.CurrentCount == 0, "Caller should hold the _sendFrameAsyncLock"); + + // If we get here, the cancellation token is not cancelable so we don't have to worry about it, + // and we own the semaphore, so we don't need to asynchronously wait for it. + Task writeTask = null; + bool releaseSemaphore = true; + try + { + // Write the payload synchronously to the buffer, then write that buffer out to the network. + int sendBytes = WriteFrameToSendBuffer(opcode, endOfMessage, payloadBuffer); + writeTask = _stream.WriteAsync(_sendBuffer, 0, sendBytes, CancellationToken.None); + + // If the operation happens to complete synchronously (or, more specifically, by + // the time we get from the previous line to here, release the semaphore, propagate + // exceptions, and we're done. + if (writeTask.IsCompleted) + { + writeTask.GetAwaiter().GetResult(); // propagate any exceptions + return CompatHelpers.CompletedTask; + } + + // Up until this point, if an exception occurred (such as when accessing _stream or when + // calling GetResult), we want to release the semaphore. After this point, the semaphore needs + // to remain held until writeTask completes. + releaseSemaphore = false; + } + catch (Exception exc) + { + return CompatHelpers.FromException(_state == WebSocketState.Aborted ? + CreateOperationCanceledException(exc) : + new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc)); + } + finally + { + if (releaseSemaphore) + { + _sendFrameAsyncLock.Release(); + } + } + + // The write was not yet completed. Create and return a continuation that will + // release the semaphore and translate any exception that occurred. + return writeTask.ContinueWith((t, s) => + { + var thisRef = (ManagedWebSocket)s; + thisRef._sendFrameAsyncLock.Release(); + + try { t.GetAwaiter().GetResult(); } + catch (Exception exc) + { + throw thisRef._state == WebSocketState.Aborted ? + CreateOperationCanceledException(exc) : + new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); + } + }, this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + + private async Task SendFrameFallbackAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment payloadBuffer, CancellationToken cancellationToken) + { + await _sendFrameAsyncLock.WaitAsync().ConfigureAwait(false); + try + { + int sendBytes = WriteFrameToSendBuffer(opcode, endOfMessage, payloadBuffer); + using (cancellationToken.Register(s => ((ManagedWebSocket)s).Abort(), this)) + { + await _stream.WriteAsync(_sendBuffer, 0, sendBytes, cancellationToken).ConfigureAwait(false); + } + } + catch (Exception exc) + { + throw _state == WebSocketState.Aborted ? + CreateOperationCanceledException(exc, cancellationToken) : + new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); + } + finally + { + _sendFrameAsyncLock.Release(); + } + } + + /// Writes a frame into the send buffer, which can then be sent over the network. + private int WriteFrameToSendBuffer(MessageOpcode opcode, bool endOfMessage, ArraySegment payloadBuffer) + { + // Grow our send buffer as needed. We reuse the buffer for all messages, with it protected by the send frame lock. + EnsureBufferLength(ref _sendBuffer, payloadBuffer.Count + MaxMessageHeaderLength); + + // Write the message header data to the buffer. + int headerLength; + int? maskOffset = null; + if (_isServer) + { + // The server doesn't send a mask, so the mask offset returned by WriteHeader + // is actually the end of the header. + headerLength = WriteHeader(opcode, _sendBuffer, payloadBuffer, endOfMessage, useMask: false); + } + else + { + // We need to know where the mask starts so that we can use the mask to manipulate the payload data, + // and we need to know the total length for sending it on the wire. + maskOffset = WriteHeader(opcode, _sendBuffer, payloadBuffer, endOfMessage, useMask: true); + headerLength = maskOffset.GetValueOrDefault() + MaskLength; + } + + // Write the payload + if (payloadBuffer.Count > 0) + { + Buffer.BlockCopy(payloadBuffer.Array, payloadBuffer.Offset, _sendBuffer, headerLength, payloadBuffer.Count); + + // If we added a mask to the header, XOR the payload with the mask. We do the manipulation in the send buffer so as to avoid + // changing the data in the caller-supplied payload buffer. + if (maskOffset.HasValue) + { + ApplyMask(_sendBuffer, headerLength, _sendBuffer, maskOffset.Value, 0, payloadBuffer.Count); + } + } + + // Return the number of bytes in the send buffer + return headerLength + payloadBuffer.Count; + } + + private void SendKeepAliveFrameAsync() + { + bool acquiredLock = _sendFrameAsyncLock.Wait(0); + if (acquiredLock) + { + // This exists purely to keep the connection alive; don't wait for the result, and ignore any failures. + // The call will handle releasing the lock. + SendFrameLockAcquiredNonCancelableAsync(MessageOpcode.Ping, true, new ArraySegment(CompatHelpers.Empty())); + } + else + { + // If the lock is already held, something is already getting sent, + // so there's no need to send a keep-alive ping. + } + } + + private static int WriteHeader(MessageOpcode opcode, byte[] sendBuffer, ArraySegment payload, bool endOfMessage, bool useMask) + { + // Client header format: + // 1 bit - FIN - 1 if this is the final fragment in the message (it could be the only fragment), otherwise 0 + // 1 bit - RSV1 - Reserved - 0 + // 1 bit - RSV2 - Reserved - 0 + // 1 bit - RSV3 - Reserved - 0 + // 4 bits - Opcode - How to interpret the payload + // - 0x0 - continuation + // - 0x1 - text + // - 0x2 - binary + // - 0x8 - connection close + // - 0x9 - ping + // - 0xA - pong + // - (0x3 to 0x7, 0xB-0xF - reserved) + // 1 bit - Masked - 1 if the payload is masked, 0 if it's not. Must be 1 for the client + // 7 bits, 7+16 bits, or 7+64 bits - Payload length + // - For length 0 through 125, 7 bits storing the length + // - For lengths 126 through 2^16, 7 bits storing the value 126, followed by 16 bits storing the length + // - For lengths 2^16+1 through 2^64, 7 bits storing the value 127, followed by 64 bytes storing the length + // 0 or 4 bytes - Mask, if Masked is 1 - random value XOR'd with each 4 bytes of the payload, round-robin + // Length bytes - Payload data + + Debug.Assert(sendBuffer.Length >= MaxMessageHeaderLength, $"Expected sendBuffer to be at least {MaxMessageHeaderLength}, got {sendBuffer.Length}"); + + sendBuffer[0] = (byte)opcode; // 4 bits for the opcode + if (endOfMessage) + { + sendBuffer[0] |= 0x80; // 1 bit for FIN + } + + // Store the payload length. + int maskOffset; + if (payload.Count <= 125) + { + sendBuffer[1] = (byte)payload.Count; + maskOffset = 2; // no additional payload length + } + else if (payload.Count <= ushort.MaxValue) + { + sendBuffer[1] = 126; + sendBuffer[2] = (byte)(payload.Count / 256); + sendBuffer[3] = (byte)payload.Count; + maskOffset = 2 + sizeof(ushort); // additional 2 bytes for 16-bit length + } + else + { + sendBuffer[1] = 127; + int length = payload.Count; + for (int i = 9; i >= 2; i--) + { + sendBuffer[i] = (byte)length; + length = length / 256; + } + maskOffset = 2 + sizeof(ulong); // additional 8 bytes for 64-bit length + } + + if (useMask) + { + // Generate the mask. + sendBuffer[1] |= 0x80; + WriteRandomMask(sendBuffer, maskOffset); + } + + // Return the position of the mask. + return maskOffset; + } + + /// Writes a 4-byte random mask to the specified buffer at the specified offset. + /// The buffer to which to write the mask. + /// The offset into the buffer at which to write the mask. + private static void WriteRandomMask(byte[] buffer, int offset) + { + byte[] mask = t_headerMask ?? (t_headerMask = new byte[MaskLength]); + Debug.Assert(mask.Length == MaskLength, $"Expected mask of length {MaskLength}, got {mask.Length}"); + s_random.GetBytes(mask); + Buffer.BlockCopy(mask, 0, buffer, offset, MaskLength); + } + + /// + /// Receive the next text, binary, continuation, or close message, returning information about it and + /// writing its payload into the supplied buffer. Other control messages may be consumed and processed + /// as part of this operation, but data about them will not be returned. + /// + /// The buffer into which payload data should be written. + /// The CancellationToken used to cancel the websocket. + /// Information about the received message. + private async Task ReceiveAsyncPrivate(ArraySegment payloadBuffer, CancellationToken cancellationToken) + { + // This is a long method. While splitting it up into pieces would arguably help with readability, doing so would + // also result in more allocations, as each async method that yields ends up with multiple allocations. The impact + // of those allocations is amortized across all of the awaits in the method, and since we generally expect a receive + // operation to require at most a single yield (while waiting for data to arrive), it's more efficient to have + // everything in the one method. We do separate out pieces for handling close and ping/pong messages, as we expect + // those to be much less frequent (e.g. we should only get one close per websocket), and thus we can afford to pay + // a bit more for readability and maintainability. + + CancellationTokenRegistration registration = cancellationToken.Register(s => ((ManagedWebSocket)s).Abort(), this); + try + { + while (true) // in case we get control frames that should be ignored from the user's perspective + { + // Get the last received header. If its payload length is non-zero, that means we previously + // received the header but were only able to read a part of the fragment, so we should skip + // reading another header and just proceed to use that same header and read more data associated + // with it. If instead its payload length is zero, then we've completed the processing of + // thta message, and we should read the next header. + MessageHeader header = _lastReceiveHeader; + if (header.PayloadLength == 0) + { + if (_receiveBufferCount < (_isServer ? (MaxMessageHeaderLength - MaskLength) : MaxMessageHeaderLength)) + { + // Make sure we have the first two bytes, which includes the start of the payload length. + if (_receiveBufferCount < 2) + { + await EnsureBufferContainsAsync(2, cancellationToken, throwOnPrematureClosure: false).ConfigureAwait(false); + if (_receiveBufferCount < 2) + { + // The connection closed; nothing more to read. + return new WebSocketReceiveResult(0, WebSocketMessageType.Text, true); + } + } + + // Then make sure we have the full header based on the payload length. + // If this is the server, we also need room for the received mask. + long payloadLength = _receiveBuffer[_receiveBufferOffset + 1] & 0x7F; + if (_isServer || payloadLength > 125) + { + int minNeeded = + 2 + + (_isServer ? MaskLength : 0) + + (payloadLength <= 125 ? 0 : payloadLength == 126 ? sizeof(ushort) : sizeof(ulong)); // additional 2 or 8 bytes for 16-bit or 64-bit length + await EnsureBufferContainsAsync(minNeeded, cancellationToken).ConfigureAwait(false); + } + } + + if (!TryParseMessageHeaderFromReceiveBuffer(out header)) + { + await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false); + } + _receivedMaskOffsetOffset = 0; + } + + // If the header represents a ping or a pong, it's a control message meant + // to be transparent to the user, so handle it and then loop around to read again. + // Alternatively, if it's a close message, handle it and exit. + if (header.Opcode == MessageOpcode.Ping || header.Opcode == MessageOpcode.Pong) + { + await HandleReceivedPingPongAsync(header, cancellationToken).ConfigureAwait(false); + continue; + } + else if (header.Opcode == MessageOpcode.Close) + { + return await HandleReceivedCloseAsync(header, cancellationToken).ConfigureAwait(false); + } + + // If this is a continuation, replace the opcode with the one of the message it's continuing + if (header.Opcode == MessageOpcode.Continuation) + { + header.Opcode = _lastReceiveHeader.Opcode; + } + + // The message should now be a binary or text message. Handle it by reading the payload and returning the contents. + Debug.Assert(header.Opcode == MessageOpcode.Binary || header.Opcode == MessageOpcode.Text, $"Unexpected opcode {header.Opcode}"); + + // If there's no data to read, return an appropriate result. + int bytesToRead = (int)Math.Min(payloadBuffer.Count, header.PayloadLength); + if (bytesToRead == 0) + { + _lastReceiveHeader = header; + return new WebSocketReceiveResult( + 0, + header.Opcode == MessageOpcode.Text ? WebSocketMessageType.Text : WebSocketMessageType.Binary, + header.PayloadLength == 0 ? header.Fin : false); + } + + // Otherwise, read as much of the payload as we can efficiently, and upate the header to reflect how much data + // remains for future reads. + + if (_receiveBufferCount == 0) + { + await EnsureBufferContainsAsync(1, cancellationToken, throwOnPrematureClosure: false).ConfigureAwait(false); + } + + int bytesToCopy = Math.Min(bytesToRead, _receiveBufferCount); + if (_isServer) + { + _receivedMaskOffsetOffset = ApplyMask(_receiveBuffer, _receiveBufferOffset, header.Mask, _receivedMaskOffsetOffset, bytesToCopy); + } + Buffer.BlockCopy(_receiveBuffer, _receiveBufferOffset, payloadBuffer.Array, payloadBuffer.Offset, bytesToCopy); + ConsumeFromBuffer(bytesToCopy); + header.PayloadLength -= bytesToCopy; + + // If this a text message, validate that it contains valid UTF8. + if (header.Opcode == MessageOpcode.Text && + !TryValidateUtf8(new ArraySegment(payloadBuffer.Array, payloadBuffer.Offset, bytesToCopy), header.Fin, _utf8TextState)) + { + await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.InvalidPayloadData, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false); + } + + _lastReceiveHeader = header; + return new WebSocketReceiveResult( + bytesToCopy, + header.Opcode == MessageOpcode.Text ? WebSocketMessageType.Text : WebSocketMessageType.Binary, + bytesToCopy == 0 || (header.Fin && header.PayloadLength == 0)); + } + } + catch (Exception exc) + { + throw _state == WebSocketState.Aborted ? + new WebSocketException(WebSocketError.InvalidState, SR.Format(SR.net_WebSockets_InvalidState_ClosedOrAborted, "System.Net.WebSockets.InternalClientWebSocket", "Aborted"), exc) : + new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); + } + finally + { + registration.Dispose(); + } + } + + /// Processes a received close message. + /// The message header. + /// The cancellation token to use to cancel the websocket. + /// The received result message. + private async Task HandleReceivedCloseAsync( + MessageHeader header, CancellationToken cancellationToken) + { + lock (StateUpdateLock) + { + _receivedCloseFrame = true; + if (_state < WebSocketState.CloseReceived) + { + _state = WebSocketState.CloseReceived; + } + } + + WebSocketCloseStatus closeStatus = WebSocketCloseStatus.NormalClosure; + string closeStatusDescription = string.Empty; + + // Handle any payload by parsing it into the close status and description. + if (header.PayloadLength == 1) + { + // The close payload length can be 0 or >= 2, but not 1. + await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false); + } + else if (header.PayloadLength >= 2) + { + if (_receiveBufferCount < header.PayloadLength) + { + await EnsureBufferContainsAsync((int)header.PayloadLength, cancellationToken).ConfigureAwait(false); + } + + if (_isServer) + { + ApplyMask(_receiveBuffer, _receiveBufferOffset, header.Mask, 0, header.PayloadLength); + } + + closeStatus = (WebSocketCloseStatus)(_receiveBuffer[_receiveBufferOffset] << 8 | _receiveBuffer[_receiveBufferOffset + 1]); + if (!IsValidCloseStatus(closeStatus)) + { + await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false); + } + + if (header.PayloadLength > 2) + { + try + { + closeStatusDescription = s_textEncoding.GetString(_receiveBuffer, _receiveBufferOffset + 2, (int)header.PayloadLength - 2); + } + catch (DecoderFallbackException exc) + { + await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken, exc).ConfigureAwait(false); + } + } + ConsumeFromBuffer((int)header.PayloadLength); + } + + // Store the close status and description onto the instance. + _closeStatus = closeStatus; + _closeStatusDescription = closeStatusDescription; + + // And return them as part of the result message. + return new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, closeStatus, closeStatusDescription); + } + + /// Processes a received ping or pong message. + /// The message header. + /// The cancellation token to use to cancel the websocket. + private async Task HandleReceivedPingPongAsync(MessageHeader header, CancellationToken cancellationToken) + { + // Consume any (optional) payload associated with the ping/pong. + if (header.PayloadLength > 0 && _receiveBufferCount < header.PayloadLength) + { + await EnsureBufferContainsAsync((int)header.PayloadLength, cancellationToken).ConfigureAwait(false); + } + + // If this was a ping, send back a pong response. + if (header.Opcode == MessageOpcode.Ping) + { + if (_isServer) + { + ApplyMask(_receiveBuffer, _receiveBufferOffset, header.Mask, 0, header.PayloadLength); + } + + await SendFrameAsync( + MessageOpcode.Pong, true, + new ArraySegment(_receiveBuffer, _receiveBufferOffset, (int)header.PayloadLength), cancellationToken).ConfigureAwait(false); + } + + // Regardless of whether it was a ping or pong, we no longer need the payload. + if (header.PayloadLength > 0) + { + ConsumeFromBuffer((int)header.PayloadLength); + } + } + + /// Check whether a close status is valid according to the RFC. + /// The status to validate. + /// true if the status if valid; otherwise, false. + private static bool IsValidCloseStatus(WebSocketCloseStatus closeStatus) + { + // 0-999: "not used" + // 1000-2999: reserved for the protocol; we need to check individual codes manually + // 3000-3999: reserved for use by higher-level code + // 4000-4999: reserved for private use + // 5000-: not mentioned in RFC + + if (closeStatus < (WebSocketCloseStatus)1000 || closeStatus >= (WebSocketCloseStatus)5000) + { + return false; + } + + if (closeStatus >= (WebSocketCloseStatus)3000) + { + return true; + } + + switch (closeStatus) // check for the 1000-2999 range known codes + { + case WebSocketCloseStatus.EndpointUnavailable: + case WebSocketCloseStatus.InternalServerError: + case WebSocketCloseStatus.InvalidMessageType: + case WebSocketCloseStatus.InvalidPayloadData: + case WebSocketCloseStatus.MandatoryExtension: + case WebSocketCloseStatus.MessageTooBig: + case WebSocketCloseStatus.NormalClosure: + case WebSocketCloseStatus.PolicyViolation: + case WebSocketCloseStatus.ProtocolError: + return true; + + default: + return false; + } + } + + /// Send a close message to the server and throw an exception, in response to getting bad data from the server. + /// The close status code to use. + /// The error reason. + /// The CancellationToken used to cancel the websocket. + /// An optional inner exception to include in the thrown exception. + private async Task CloseWithReceiveErrorAndThrowAsync( + WebSocketCloseStatus closeStatus, WebSocketError error, CancellationToken cancellationToken, Exception innerException = null) + { + // Close the connection if it hasn't already been closed + if (!_sentCloseFrame) + { + await CloseOutputAsync(closeStatus, string.Empty, cancellationToken).ConfigureAwait(false); + } + + // Dump our receive buffer; we're in a bad state to do any further processing + _receiveBufferCount = 0; + + // Let the caller know we've failed + throw new WebSocketException(error, innerException); + } + + /// Parses a message header from the buffer. This assumes the header is in the buffer. + /// The read header. + /// true if a header was read; false if the header was invalid. + private bool TryParseMessageHeaderFromReceiveBuffer(out MessageHeader resultHeader) + { + Debug.Assert(_receiveBufferCount >= 2, $"Expected to at least have the first two bytes of the header."); + + var header = new MessageHeader(); + + header.Fin = (_receiveBuffer[_receiveBufferOffset] & 0x80) != 0; + bool reservedSet = (_receiveBuffer[_receiveBufferOffset] & 0x70) != 0; + header.Opcode = (MessageOpcode)(_receiveBuffer[_receiveBufferOffset] & 0xF); + + bool masked = (_receiveBuffer[_receiveBufferOffset + 1] & 0x80) != 0; + header.PayloadLength = _receiveBuffer[_receiveBufferOffset + 1] & 0x7F; + + ConsumeFromBuffer(2); + + // Read the remainder of the payload length, if necessary + if (header.PayloadLength == 126) + { + Debug.Assert(_receiveBufferCount >= 2, $"Expected to have two bytes for the payload length."); + header.PayloadLength = (_receiveBuffer[_receiveBufferOffset] << 8) | _receiveBuffer[_receiveBufferOffset + 1]; + ConsumeFromBuffer(2); + } + else if (header.PayloadLength == 127) + { + Debug.Assert(_receiveBufferCount >= 8, $"Expected to have eight bytes for the payload length."); + header.PayloadLength = 0; + for (int i = 0; i < 8; i++) + { + header.PayloadLength = (header.PayloadLength << 8) | _receiveBuffer[_receiveBufferOffset + i]; + } + ConsumeFromBuffer(8); + } + + bool shouldFail = reservedSet; + if (masked) + { + if (!_isServer) + { + shouldFail = true; + } + header.Mask = CombineMaskBytes(_receiveBuffer, _receiveBufferOffset); + + // Consume the mask bytes + ConsumeFromBuffer(4); + } + + // Do basic validation of the header + switch (header.Opcode) + { + case MessageOpcode.Continuation: + if (_lastReceiveHeader.Fin) + { + // Can't continue from a final message + shouldFail = true; + } + break; + + case MessageOpcode.Binary: + case MessageOpcode.Text: + if (!_lastReceiveHeader.Fin) + { + // Must continue from a non-final message + shouldFail = true; + } + break; + + case MessageOpcode.Close: + case MessageOpcode.Ping: + case MessageOpcode.Pong: + if (header.PayloadLength > MaxControlPayloadLength || !header.Fin) + { + // Invalid control messgae + shouldFail = true; + } + break; + + default: + // Unknown opcode + shouldFail = true; + break; + } + + // Return the read header + resultHeader = header; + return !shouldFail; + } + + /// Send a close message, then receive until we get a close response message. + /// The close status to send. + /// The close status description to send. + /// The CancellationToken to use to cancel the websocket. + private async Task CloseAsyncPrivate(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) + { + // Send the close message. Skip sending a close frame if we're currently in a CloseSent state, + // for example having just done a CloseOutputAsync. + if (!_sentCloseFrame) + { + await SendCloseFrameAsync(closeStatus, statusDescription, cancellationToken).ConfigureAwait(false); + } + + // We should now either be in a CloseSent case (because we just sent one), or in a CloseReceived state, in case + // there was a concurrent receive that ended up handling an immediate close frame response from the server. + // Of course it could also be Aborted if something happened concurrently to cause things to blow up. + Debug.Assert( + State == WebSocketState.CloseSent || + State == WebSocketState.CloseReceived || + State == WebSocketState.Aborted, + $"Unexpected state {State}."); + + // Wait until we've received a close response + byte[] closeBuffer = new byte[MaxMessageHeaderLength + MaxControlPayloadLength]; + while (!_receivedCloseFrame) + { + Debug.Assert(!Monitor.IsEntered(StateUpdateLock), $"{nameof(StateUpdateLock)} must never be held when acquiring {nameof(ReceiveAsyncLock)}"); + Task receiveTask; + lock (ReceiveAsyncLock) + { + // Now that we're holding the ReceiveAsyncLock, double-check that we've not yet received the close frame. + // It could have been received between our check above and now due to a concurrent receive completing. + if (_receivedCloseFrame) + { + break; + } + + // We've not yet processed a received close frame, which means we need to wait for a received close to complete. + // There may already be one in flight, in which case we want to just wait for that one rather than kicking off + // another (we don't support concurrent receive operations). We need to kick off a new receive if either we've + // never issued a receive or if the last issued receive completed for reasons other than a close frame. There is + // a race condition here, e.g. if there's a in-flight receive that completes after we check, but that's fine: worst + // case is we then await it, find that it's not what we need, and try again. + receiveTask = _lastReceiveAsync; + if (receiveTask == null || + (receiveTask.Status == TaskStatus.RanToCompletion && receiveTask.Result.MessageType != WebSocketMessageType.Close)) + { + _lastReceiveAsync = receiveTask = ReceiveAsyncPrivate(new ArraySegment(closeBuffer), cancellationToken); + } + } + + // Wait for whatever receive task we have. We'll then loop around again to re-check our state. + Debug.Assert(receiveTask != null); + await receiveTask.ConfigureAwait(false); + } + + // We're closed. Close the connection and update the status. + lock (StateUpdateLock) + { + DisposeCore(); + if (_state < WebSocketState.Closed) + { + _state = WebSocketState.Closed; + } + } + } + + /// Sends a close message to the server. + /// The close status to send. + /// The close status description to send. + /// The CancellationToken to use to cancel the websocket. + private async Task SendCloseFrameAsync(WebSocketCloseStatus closeStatus, string closeStatusDescription, CancellationToken cancellationToken) + { + // Close payload is two bytes containing the close status followed by a UTF8-encoding of the status description, if it exists. + + byte[] buffer; + if (string.IsNullOrEmpty(closeStatusDescription)) + { + buffer = new byte[2]; + } + else + { + buffer = new byte[2 + s_textEncoding.GetByteCount(closeStatusDescription)]; + int encodedLength = s_textEncoding.GetBytes(closeStatusDescription, 0, closeStatusDescription.Length, buffer, 2); + Debug.Assert(buffer.Length - 2 == encodedLength, $"GetByteCount and GetBytes encoded count didn't match"); + } + + ushort closeStatusValue = (ushort)closeStatus; + buffer[0] = (byte)(closeStatusValue >> 8); + buffer[1] = (byte)(closeStatusValue & 0xFF); + + await SendFrameAsync(MessageOpcode.Close, true, new ArraySegment(buffer), cancellationToken).ConfigureAwait(false); + + lock (StateUpdateLock) + { + _sentCloseFrame = true; + if (_state <= WebSocketState.CloseReceived) + { + _state = WebSocketState.CloseSent; + } + } + } + + private void ConsumeFromBuffer(int count) + { + Debug.Assert(count >= 0, $"Expected non-negative count, got {count}"); + Debug.Assert(count <= _receiveBufferCount, $"Trying to consume {count}, which is more than exists {_receiveBufferCount}"); + _receiveBufferCount -= count; + _receiveBufferOffset += count; + } + + private async Task EnsureBufferContainsAsync(int minimumRequiredBytes, CancellationToken cancellationToken, bool throwOnPrematureClosure = true) + { + Debug.Assert(minimumRequiredBytes <= _receiveBuffer.Length, $"Requested number of bytes {minimumRequiredBytes} must not exceed {_receiveBuffer.Length}"); + + // If we don't have enough data in the buffer to satisfy the minimum required, read some more. + if (_receiveBufferCount < minimumRequiredBytes) + { + // If there's any data in the buffer, shift it down. + if (_receiveBufferCount > 0) + { + Buffer.BlockCopy(_receiveBuffer, _receiveBufferOffset, _receiveBuffer, 0, _receiveBufferCount); + } + _receiveBufferOffset = 0; + + // While we don't have enough data, read more. + while (_receiveBufferCount < minimumRequiredBytes) + { + int numRead = await _stream.ReadAsync(_receiveBuffer, _receiveBufferCount, _receiveBuffer.Length - _receiveBufferCount, cancellationToken).ConfigureAwait(false); + Debug.Assert(numRead >= 0, $"Expected non-negative bytes read, got {numRead}"); + _receiveBufferCount += numRead; + if (numRead == 0) + { + // The connection closed before we were able to read everything we needed. + // If it was due to use being disposed, fail. If it was due to the connection + // being closed and it wasn't expected, fail. If it was due to the connection + // being closed and that was expected, exit gracefully. + if (_disposed) + { + throw new ObjectDisposedException("ClientWebSocket"); + } + else if (throwOnPrematureClosure) + { + throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely); + } + break; + } + } + } + } + + /// + /// Grows the specified buffer if it's not at least the specified minimum length. + /// Data is not copied if the buffer is grown. + /// + private static void EnsureBufferLength(ref byte[] buffer, int minLength) + { + if (buffer == null || buffer.Length < minLength) + { + buffer = new byte[minLength]; + } + } + + private static unsafe int CombineMaskBytes(byte[] buffer, int maskOffset) => + BitConverter.ToInt32(buffer, maskOffset); + + /// Applies a mask to a portion of a byte array. + /// The buffer to which the mask should be applied. + /// The offset into at which the mask should start to be applied. + /// The array containing the mask to apply. + /// The offset into of the mask to apply of length . + /// The next position offset from of which by to apply next from the mask. + /// The number of bytes starting from to which the mask should be applied. + /// The updated maskOffsetOffset value. + private static int ApplyMask(byte[] toMask, int toMaskOffset, byte[] mask, int maskOffset, int maskOffsetIndex, long count) + { + Debug.Assert(maskOffsetIndex < MaskLength, $"Unexpected {nameof(maskOffsetIndex)}: {maskOffsetIndex}"); + Debug.Assert(mask.Length >= MaskLength + maskOffset, $"Unexpected inputs: {mask.Length}, {maskOffset}"); + return ApplyMask(toMask, toMaskOffset, CombineMaskBytes(mask, maskOffset), maskOffsetIndex, count); + } + + /// Applies a mask to a portion of a byte array. + /// The buffer to which the mask should be applied. + /// The offset into at which the mask should start to be applied. + /// The four-byte mask, stored as an Int32. + /// The index into the mas + /// The number of bytes to mask. + /// + private static unsafe int ApplyMask(byte[] toMask, int toMaskOffset, int mask, int maskIndex, long count) + { + Debug.Assert(toMaskOffset <= toMask.Length - count, $"Unexpected inputs: {toMaskOffset}, {toMask.Length}, {count}"); + Debug.Assert(maskIndex < sizeof(int), $"Unexpected {nameof(maskIndex)}: {maskIndex}"); + + byte* maskPtr = (byte*)&mask; + fixed (byte* toMaskPtr = toMask) + { + byte* p = toMaskPtr + toMaskOffset; + byte* end = p + count; + while (p < end) + { + *p++ ^= maskPtr[maskIndex]; + maskIndex = (maskIndex + 1) & 3; // & 3 == faster % MaskLength + } + return maskIndex; + } + } + + /// Aborts the websocket and throws an exception if an existing operation is in progress. + private void ThrowIfOperationInProgress(Task operationTask, [CallerMemberName] string methodName = null) + { + if (operationTask != null && !operationTask.IsCompleted) + { + Abort(); + throw new InvalidOperationException(SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, methodName)); + } + } + + /// Creates an OperationCanceledException instance, using a default message and the specified inner exception and token. + private static Exception CreateOperationCanceledException(Exception innerException, CancellationToken cancellationToken = default(CancellationToken)) + { + return new OperationCanceledException( + new OperationCanceledException().Message, + innerException, + cancellationToken); + } + + // From https://raw.githubusercontent.com/aspnet/WebSockets/dev/src/Microsoft.AspNetCore.WebSockets.Protocol/Utilities.cs + // Performs a stateful validation of UTF-8 bytes. + // It checks for valid formatting, overlong encodings, surrogates, and value ranges. + private static bool TryValidateUtf8(ArraySegment arraySegment, bool endOfMessage, Utf8MessageState state) + { + for (int i = arraySegment.Offset; i < arraySegment.Offset + arraySegment.Count;) + { + // Have we started a character sequence yet? + if (!state.SequenceInProgress) + { + // The first byte tells us how many bytes are in the sequence. + state.SequenceInProgress = true; + byte b = arraySegment.Array[i]; + i++; + if ((b & 0x80) == 0) // 0bbbbbbb, single byte + { + state.AdditionalBytesExpected = 0; + state.CurrentDecodeBits = b & 0x7F; + state.ExpectedValueMin = 0; + } + else if ((b & 0xC0) == 0x80) + { + // Misplaced 10bbbbbb continuation byte. This cannot be the first byte. + return false; + } + else if ((b & 0xE0) == 0xC0) // 110bbbbb 10bbbbbb + { + state.AdditionalBytesExpected = 1; + state.CurrentDecodeBits = b & 0x1F; + state.ExpectedValueMin = 0x80; + } + else if ((b & 0xF0) == 0xE0) // 1110bbbb 10bbbbbb 10bbbbbb + { + state.AdditionalBytesExpected = 2; + state.CurrentDecodeBits = b & 0xF; + state.ExpectedValueMin = 0x800; + } + else if ((b & 0xF8) == 0xF0) // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + { + state.AdditionalBytesExpected = 3; + state.CurrentDecodeBits = b & 0x7; + state.ExpectedValueMin = 0x10000; + } + else // 111110bb & 1111110b & 11111110 && 11111111 are not valid + { + return false; + } + } + while (state.AdditionalBytesExpected > 0 && i < arraySegment.Offset + arraySegment.Count) + { + byte b = arraySegment.Array[i]; + if ((b & 0xC0) != 0x80) + { + return false; + } + + i++; + state.AdditionalBytesExpected--; + + // Each continuation byte carries 6 bits of data 0x10bbbbbb. + state.CurrentDecodeBits = (state.CurrentDecodeBits << 6) | (b & 0x3F); + + if (state.AdditionalBytesExpected == 1 && state.CurrentDecodeBits >= 0x360 && state.CurrentDecodeBits <= 0x37F) + { + // This is going to end up in the range of 0xD800-0xDFFF UTF-16 surrogates that are not allowed in UTF-8; + return false; + } + if (state.AdditionalBytesExpected == 2 && state.CurrentDecodeBits >= 0x110) + { + // This is going to be out of the upper Unicode bound 0x10FFFF. + return false; + } + } + if (state.AdditionalBytesExpected == 0) + { + state.SequenceInProgress = false; + if (state.CurrentDecodeBits < state.ExpectedValueMin) + { + // Overlong encoding (e.g. using 2 bytes to encode something that only needed 1). + return false; + } + } + } + if (endOfMessage && state.SequenceInProgress) + { + return false; + } + return true; + } + + private sealed class Utf8MessageState + { + internal bool SequenceInProgress; + internal int AdditionalBytesExpected; + internal int ExpectedValueMin; + internal int CurrentDecodeBits; + } + + private enum MessageOpcode : byte + { + Continuation = 0x0, + Text = 0x1, + Binary = 0x2, + Close = 0x8, + Ping = 0x9, + Pong = 0xA + } + + [StructLayout(LayoutKind.Auto)] + private struct MessageHeader + { + internal MessageOpcode Opcode; + internal bool Fin; + internal long PayloadLength; + internal int Mask; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index ac4ff9de65..e82ad375c9 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -10,7 +10,9 @@ "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", "nowarn": [ - "CS1591" + "CS1591", + "CS1572", + "CS1573" ], "xmlDoc": true }, @@ -31,6 +33,7 @@ "System.IO": "4.1.0-*", "System.IO.FileSystem": "4.0.1-*", "System.Net.Primitives": "4.0.11-*", + "System.Net.WebSockets": "4.0.0-*", "System.Runtime.Extensions": "4.1.0-*", "System.Runtime.InteropServices": "4.1.0-*", "System.Security.Claims": "4.0.1-*", @@ -38,7 +41,8 @@ "System.Security.Principal.Windows": "4.0.0-*", "System.Text.Encoding.Extensions": "4.0.11-*", "System.Threading": "4.0.11-*", - "System.Threading.Overlapped": "4.0.1-*" + "System.Threading.Overlapped": "4.0.1-*", + "System.Threading.Timer": "4.0.1" } } } diff --git a/src/Microsoft.Net.WebSockets.Server/HttpKnownHeaderNames.cs b/src/Microsoft.Net.WebSockets.Server/HttpKnownHeaderNames.cs deleted file mode 100644 index fb6fa1d755..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/HttpKnownHeaderNames.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.Net.WebSockets -{ - // this class contains known header names - internal static class HttpKnownHeaderNames - { - public const string CacheControl = "Cache-Control"; - public const string Connection = "Connection"; - public const string Date = "Date"; - public const string KeepAlive = "Keep-Alive"; - public const string Pragma = "Pragma"; - public const string ProxyConnection = "Proxy-Connection"; - public const string Trailer = "Trailer"; - public const string TransferEncoding = "Transfer-Encoding"; - public const string Upgrade = "Upgrade"; - public const string Via = "Via"; - public const string Warning = "Warning"; - public const string ContentLength = "Content-Length"; - public const string ContentType = "Content-Type"; - public const string ContentDisposition = "Content-Disposition"; - public const string ContentEncoding = "Content-Encoding"; - public const string ContentLanguage = "Content-Language"; - public const string ContentLocation = "Content-Location"; - public const string ContentRange = "Content-Range"; - public const string Expires = "Expires"; - public const string LastModified = "Last-Modified"; - public const string Age = "Age"; - public const string Location = "Location"; - public const string ProxyAuthenticate = "Proxy-Authenticate"; - public const string RetryAfter = "Retry-After"; - public const string Server = "Server"; - public const string SetCookie = "Set-Cookie"; - public const string SetCookie2 = "Set-Cookie2"; - public const string Vary = "Vary"; - public const string WWWAuthenticate = "WWW-Authenticate"; - public const string Accept = "Accept"; - public const string AcceptCharset = "Accept-Charset"; - public const string AcceptEncoding = "Accept-Encoding"; - public const string AcceptLanguage = "Accept-Language"; - public const string Authorization = "Authorization"; - public const string Cookie = "Cookie"; - public const string Cookie2 = "Cookie2"; - public const string Expect = "Expect"; - public const string From = "From"; - public const string Host = "Host"; - public const string IfMatch = "If-Match"; - public const string IfModifiedSince = "If-Modified-Since"; - public const string IfNoneMatch = "If-None-Match"; - public const string IfRange = "If-Range"; - public const string IfUnmodifiedSince = "If-Unmodified-Since"; - public const string MaxForwards = "Max-Forwards"; - public const string ProxyAuthorization = "Proxy-Authorization"; - public const string Referer = "Referer"; - public const string Range = "Range"; - public const string UserAgent = "User-Agent"; - public const string ContentMD5 = "Content-MD5"; - public const string ETag = "ETag"; - public const string TE = "TE"; - public const string Allow = "Allow"; - public const string AcceptRanges = "Accept-Ranges"; - public const string P3P = "P3P"; - public const string XPoweredBy = "X-Powered-By"; - public const string XAspNetVersion = "X-AspNet-Version"; - public const string SecWebSocketKey = "Sec-WebSocket-Key"; - public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions"; - public const string SecWebSocketAccept = "Sec-WebSocket-Accept"; - public const string Origin = "Origin"; - public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol"; - public const string SecWebSocketVersion = "Sec-WebSocket-Version"; - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/Legacy/SR.cs b/src/Microsoft.Net.WebSockets.Server/Legacy/SR.cs deleted file mode 100644 index 6062f60855..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/Legacy/SR.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All Rights Reserved. -// Information Contained Herein is Proprietary and Confidential. -// -//------------------------------------------------------------------------------ - -namespace System -{ - internal sealed class SR - { - internal const string net_servicePointAddressNotSupportedInHostMode = "net_servicePointAddressNotSupportedInHostMode"; - internal const string net_Websockets_AlreadyOneOutstandingOperation = "net_Websockets_AlreadyOneOutstandingOperation"; - internal const string net_Websockets_WebSocketBaseFaulted = "net_Websockets_WebSocketBaseFaulted"; - internal const string net_WebSockets_NativeSendResponseHeaders = "net_WebSockets_NativeSendResponseHeaders"; - internal const string net_WebSockets_Generic = "net_WebSockets_Generic"; - internal const string net_WebSockets_NotAWebSocket_Generic = "net_WebSockets_NotAWebSocket_Generic"; - internal const string net_WebSockets_UnsupportedWebSocketVersion_Generic = "net_WebSockets_UnsupportedWebSocketVersion_Generic"; - internal const string net_WebSockets_HeaderError_Generic = "net_WebSockets_HeaderError_Generic"; - internal const string net_WebSockets_UnsupportedProtocol_Generic = "net_WebSockets_UnsupportedProtocol_Generic"; - internal const string net_WebSockets_UnsupportedPlatform = "net_WebSockets_UnsupportedPlatform"; - internal const string net_WebSockets_AcceptNotAWebSocket = "net_WebSockets_AcceptNotAWebSocket"; - internal const string net_WebSockets_AcceptUnsupportedWebSocketVersion = "net_WebSockets_AcceptUnsupportedWebSocketVersion"; - internal const string net_WebSockets_AcceptHeaderNotFound = "net_WebSockets_AcceptHeaderNotFound"; - internal const string net_WebSockets_AcceptUnsupportedProtocol = "net_WebSockets_AcceptUnsupportedProtocol"; - internal const string net_WebSockets_ClientAcceptingNoProtocols = "net_WebSockets_ClientAcceptingNoProtocols"; - internal const string net_WebSockets_ClientSecWebSocketProtocolsBlank = "net_WebSockets_ClientSecWebSocketProtocolsBlank"; - internal const string net_WebSockets_ArgumentOutOfRange_TooSmall = "net_WebSockets_ArgumentOutOfRange_TooSmall"; - internal const string net_WebSockets_ArgumentOutOfRange_InternalBuffer = "net_WebSockets_ArgumentOutOfRange_InternalBuffer"; - internal const string net_WebSockets_ArgumentOutOfRange_TooBig = "net_WebSockets_ArgumentOutOfRange_TooBig"; - internal const string net_WebSockets_InvalidState_Generic = "net_WebSockets_InvalidState_Generic"; - internal const string net_WebSockets_InvalidState_ClosedOrAborted = "net_WebSockets_InvalidState_ClosedOrAborted"; - internal const string net_WebSockets_InvalidState = "net_WebSockets_InvalidState"; - internal const string net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync = "net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync"; - internal const string net_WebSockets_InvalidMessageType = "net_WebSockets_InvalidMessageType"; - internal const string net_WebSockets_InvalidBufferType = "net_WebSockets_InvalidBufferType"; - internal const string net_WebSockets_InvalidMessageType_Generic = "net_WebSockets_InvalidMessageType_Generic"; - internal const string net_WebSockets_Argument_InvalidMessageType = "net_WebSockets_Argument_InvalidMessageType"; - internal const string net_WebSockets_ConnectionClosedPrematurely_Generic = "net_WebSockets_ConnectionClosedPrematurely_Generic"; - internal const string net_WebSockets_InvalidCharInProtocolString = "net_WebSockets_InvalidCharInProtocolString"; - internal const string net_WebSockets_InvalidEmptySubProtocol = "net_WebSockets_InvalidEmptySubProtocol"; - internal const string net_WebSockets_ReasonNotNull = "net_WebSockets_ReasonNotNull"; - internal const string net_WebSockets_InvalidCloseStatusCode = "net_WebSockets_InvalidCloseStatusCode"; - internal const string net_WebSockets_InvalidCloseStatusDescription = "net_WebSockets_InvalidCloseStatusDescription"; - internal const string net_WebSockets_Scheme = "net_WebSockets_Scheme"; - internal const string net_WebSockets_AlreadyStarted = "net_WebSockets_AlreadyStarted"; - internal const string net_WebSockets_Connect101Expected = "net_WebSockets_Connect101Expected"; - internal const string net_WebSockets_InvalidResponseHeader = "net_WebSockets_InvalidResponseHeader"; - internal const string net_WebSockets_NotConnected = "net_WebSockets_NotConnected"; - internal const string net_WebSockets_InvalidRegistration = "net_WebSockets_InvalidRegistration"; - internal const string net_WebSockets_NoDuplicateProtocol = "net_WebSockets_NoDuplicateProtocol"; - - internal const string NotReadableStream = "NotReadableStream"; - internal const string NotWriteableStream = "NotWriteableStream"; - - public static string GetString(string name, params object[] args) - { - return name; - } - - public static string GetString(string name) - { - return name; - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs b/src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs deleted file mode 100644 index be72c5f88e..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/Legacy/WebSocketHttpListenerDuplexStream.cs +++ /dev/null @@ -1,1279 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ -/* -namespace Microsoft.AspNetCore.WebSockets -{ - using Microsoft.Net; - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.ComponentModel; - using System.Diagnostics; - using System.Diagnostics.Contracts; - using System.Globalization; - using System.IO; - using System.Runtime.InteropServices; - using System.Security; - using System.Threading; - using System.Threading.Tasks; - - internal class WebSocketHttpListenerDuplexStream : Stream, WebSocketBase.IWebSocketStream - { - private static readonly EventHandler s_OnReadCompleted = - new EventHandler(OnReadCompleted); - private static readonly EventHandler s_OnWriteCompleted = - new EventHandler(OnWriteCompleted); - private static readonly Func s_CanHandleException = new Func(CanHandleException); - private static readonly Action s_OnCancel = new Action(OnCancel); - // private readonly HttpRequestStream m_InputStream; - // private readonly HttpResponseStream m_OutputStream; - private HttpListenerContext m_Context; - private bool m_InOpaqueMode; - private WebSocketBase m_WebSocket; - private HttpListenerAsyncEventArgs m_WriteEventArgs; - private HttpListenerAsyncEventArgs m_ReadEventArgs; - private TaskCompletionSource m_WriteTaskCompletionSource; - private TaskCompletionSource m_ReadTaskCompletionSource; - private int m_CleanedUp; - -#if DEBUG - private class OutstandingOperations - { - internal int m_Reads; - internal int m_Writes; - } - - private readonly OutstandingOperations m_OutstandingOperations = new OutstandingOperations(); -#endif //DEBUG - - public WebSocketHttpListenerDuplexStream( - // HttpRequestStream inputStream, - // HttpResponseStream outputStream, - HttpListenerContext context) - { - Contract.Assert(inputStream != null, "'inputStream' MUST NOT be NULL."); - Contract.Assert(outputStream != null, "'outputStream' MUST NOT be NULL."); - Contract.Assert(context != null, "'context' MUST NOT be NULL."); - Contract.Assert(inputStream.CanRead, "'inputStream' MUST support read operations."); - Contract.Assert(outputStream.CanWrite, "'outputStream' MUST support write operations."); - - m_InputStream = inputStream; - m_OutputStream = outputStream; - m_Context = context; - - if (WebSocketBase.LoggingEnabled) - { - Logging.Associate(Logging.WebSockets, inputStream, this); - Logging.Associate(Logging.WebSockets, outputStream, this); - } - } - - public override bool CanRead - { - get - { - return m_InputStream.CanRead; - } - } - - public override bool CanSeek - { - get - { - return false; - } - } - - public override bool CanTimeout - { - get - { - return m_InputStream.CanTimeout && m_OutputStream.CanTimeout; - } - } - - public override bool CanWrite - { - get - { - return m_OutputStream.CanWrite; - } - } - - 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 int Read(byte[] buffer, int offset, int count) - { - return m_InputStream.Read(buffer, offset, count); - } - - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - WebSocketHelpers.ValidateBuffer(buffer, offset, count); - - return ReadAsyncCore(buffer, offset, count, cancellationToken); - } - - private async Task ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, this, Methods.ReadAsyncCore, - WebSocketHelpers.GetTraceMsgForParameters(offset, count, cancellationToken)); - } - - CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration(); - - int bytesRead = 0; - try - { - if (cancellationToken.CanBeCanceled) - { - cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); - } - - if (!m_InOpaqueMode) - { - bytesRead = await m_InputStream.ReadAsync(buffer, offset, count, cancellationToken).SuppressContextFlow(); - } - else - { -#if DEBUG - // When using fast path only one outstanding read is permitted. By switching into opaque mode - // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) - // caller takes responsibility for enforcing this constraint. - Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Reads) == 1, - "Only one outstanding read allowed at any given time."); -#endif - m_ReadTaskCompletionSource = new TaskCompletionSource(); - m_ReadEventArgs.SetBuffer(buffer, offset, count); - if (!ReadAsyncFast(m_ReadEventArgs)) - { - if (m_ReadEventArgs.Exception != null) - { - throw m_ReadEventArgs.Exception; - } - - bytesRead = m_ReadEventArgs.BytesTransferred; - } - else - { - bytesRead = await m_ReadTaskCompletionSource.Task.SuppressContextFlow(); - } - } - } - catch (Exception error) - { - if (s_CanHandleException(error)) - { - cancellationToken.ThrowIfCancellationRequested(); - } - - throw; - } - finally - { - cancellationTokenRegistration.Dispose(); - - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.ReadAsyncCore, bytesRead); - } - } - - return bytesRead; - } - - // return value indicates sync vs async completion - // false: sync completion - // true: async completion - private unsafe bool ReadAsyncFast(HttpListenerAsyncEventArgs eventArgs) - { - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, this, Methods.ReadAsyncFast, string.Empty); - } - - eventArgs.StartOperationCommon(this); - eventArgs.StartOperationReceive(); - - uint statusCode = 0; - bool completedAsynchronously = false; - try - { - Contract.Assert(eventArgs.Buffer != null, "'BufferList' is not supported for read operations."); - if (eventArgs.Count == 0 || m_InputStream.Closed) - { - eventArgs.FinishOperationSuccess(0, true); - return false; - } - - uint dataRead = 0; - int offset = eventArgs.Offset; - int remainingCount = eventArgs.Count; - - if (m_InputStream.BufferedDataChunksAvailable) - { - dataRead = m_InputStream.GetChunks(eventArgs.Buffer, eventArgs.Offset, eventArgs.Count); - if (m_InputStream.BufferedDataChunksAvailable && dataRead == eventArgs.Count) - { - eventArgs.FinishOperationSuccess(eventArgs.Count, true); - return false; - } - } - - Contract.Assert(!m_InputStream.BufferedDataChunksAvailable, "'m_InputStream.BufferedDataChunksAvailable' MUST BE 'FALSE' at this point."); - Contract.Assert(dataRead <= eventArgs.Count, "'dataRead' MUST NOT be bigger than 'eventArgs.Count'."); - - if (dataRead != 0) - { - offset += (int)dataRead; - remainingCount -= (int)dataRead; - //the http.sys team recommends that we limit the size to 128kb - if (remainingCount > HttpRequestStream.MaxReadSize) - { - remainingCount = HttpRequestStream.MaxReadSize; - } - - eventArgs.SetBuffer(eventArgs.Buffer, offset, remainingCount); - } - else if (remainingCount > HttpRequestStream.MaxReadSize) - { - remainingCount = HttpRequestStream.MaxReadSize; - eventArgs.SetBuffer(eventArgs.Buffer, offset, remainingCount); - } - - // m_InputStream.InternalHttpContext.EnsureBoundHandle(); - uint flags = 0; - uint bytesReturned = 0; - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody2( - m_InputStream.InternalHttpContext.RequestQueueHandle, - m_InputStream.InternalHttpContext.RequestId, - flags, - (byte*)m_WebSocket.InternalBuffer.ToIntPtr(eventArgs.Offset), - (uint)eventArgs.Count, - out bytesReturned, - eventArgs.NativeOverlapped); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING && - statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) - { - throw new HttpListenerException((int)statusCode); - } - else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - HttpListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously. No IO completion port callback is used because - // it was disabled in SwitchToOpaqueMode() - eventArgs.FinishOperationSuccess((int)bytesReturned, true); - completedAsynchronously = false; - } - else - { - completedAsynchronously = true; - } - } - catch (Exception e) - { - m_ReadEventArgs.FinishOperationFailure(e, true); - m_OutputStream.SetClosedFlag(); - m_OutputStream.InternalHttpContext.Abort(); - - throw; - } - finally - { - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.ReadAsyncFast, completedAsynchronously); - } - } - - return completedAsynchronously; - } - - public override int ReadByte() - { - return m_InputStream.ReadByte(); - } - - public bool SupportsMultipleWrite - { - get - { - return true; - } - } - - public override IAsyncResult BeginRead(byte[] buffer, - int offset, - int count, - AsyncCallback callback, - object state) - { - return m_InputStream.BeginRead(buffer, offset, count, callback, state); - } - - public override int EndRead(IAsyncResult asyncResult) - { - return m_InputStream.EndRead(asyncResult); - } - - public Task MultipleWriteAsync(IList> sendBuffers, CancellationToken cancellationToken) - { - Contract.Assert(m_InOpaqueMode, "The stream MUST be in opaque mode at this point."); - Contract.Assert(sendBuffers != null, "'sendBuffers' MUST NOT be NULL."); - Contract.Assert(sendBuffers.Count == 1 || sendBuffers.Count == 2, - "'sendBuffers.Count' MUST be either '1' or '2'."); - - if (sendBuffers.Count == 1) - { - ArraySegment buffer = sendBuffers[0]; - return WriteAsync(buffer.Array, buffer.Offset, buffer.Count, cancellationToken); - } - - return MultipleWriteAsyncCore(sendBuffers, cancellationToken); - } - - private async Task MultipleWriteAsyncCore(IList> sendBuffers, CancellationToken cancellationToken) - { - Contract.Assert(sendBuffers != null, "'sendBuffers' MUST NOT be NULL."); - Contract.Assert(sendBuffers.Count == 2, "'sendBuffers.Count' MUST be '2' at this point."); - - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, this, Methods.MultipleWriteAsyncCore, string.Empty); - } - - CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration(); - - try - { - if (cancellationToken.CanBeCanceled) - { - cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); - } -#if DEBUG - // When using fast path only one outstanding read is permitted. By switching into opaque mode - // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) - // caller takes responsibility for enforcing this constraint. - Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Writes) == 1, - "Only one outstanding write allowed at any given time."); -#endif - m_WriteTaskCompletionSource = new TaskCompletionSource(); - m_WriteEventArgs.SetBuffer(null, 0, 0); - m_WriteEventArgs.BufferList = sendBuffers; - if (WriteAsyncFast(m_WriteEventArgs)) - { - await m_WriteTaskCompletionSource.Task.SuppressContextFlow(); - } - } - catch (Exception error) - { - if (s_CanHandleException(error)) - { - cancellationToken.ThrowIfCancellationRequested(); - } - - throw; - } - finally - { - cancellationTokenRegistration.Dispose(); - - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.MultipleWriteAsyncCore, string.Empty); - } - } - } - - public override void Write(byte[] buffer, int offset, int count) - { - m_OutputStream.Write(buffer, offset, count); - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - WebSocketHelpers.ValidateBuffer(buffer, offset, count); - - return WriteAsyncCore(buffer, offset, count, cancellationToken); - } - - private async Task WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, this, Methods.WriteAsyncCore, - WebSocketHelpers.GetTraceMsgForParameters(offset, count, cancellationToken)); - } - - CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration(); - - try - { - if (cancellationToken.CanBeCanceled) - { - cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); - } - - if (!m_InOpaqueMode) - { - await m_OutputStream.WriteAsync(buffer, offset, count, cancellationToken).SuppressContextFlow(); - } - else - { -#if DEBUG - // When using fast path only one outstanding read is permitted. By switching into opaque mode - // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) - // caller takes responsibility for enforcing this constraint. - Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Writes) == 1, - "Only one outstanding write allowed at any given time."); -#endif - m_WriteTaskCompletionSource = new TaskCompletionSource(); - m_WriteEventArgs.BufferList = null; - m_WriteEventArgs.SetBuffer(buffer, offset, count); - if (WriteAsyncFast(m_WriteEventArgs)) - { - await m_WriteTaskCompletionSource.Task.SuppressContextFlow(); - } - } - } - catch (Exception error) - { - if (s_CanHandleException(error)) - { - cancellationToken.ThrowIfCancellationRequested(); - } - - throw; - } - finally - { - cancellationTokenRegistration.Dispose(); - - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.WriteAsyncCore, string.Empty); - } - } - } - - // return value indicates sync vs async completion - // false: sync completion - // true: async completion - private bool WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs) - { - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, this, Methods.WriteAsyncFast, string.Empty); - } - - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; - - eventArgs.StartOperationCommon(this); - eventArgs.StartOperationSend(); - - uint statusCode; - bool completedAsynchronously = false; - try - { - if (m_OutputStream.Closed || - (eventArgs.Buffer != null && eventArgs.Count == 0)) - { - eventArgs.FinishOperationSuccess(eventArgs.Count, true); - return false; - } - - if (eventArgs.ShouldCloseOutput) - { - flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; - } - else - { - flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - // When using HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA HTTP.SYS will copy the payload to - // kernel memory (Non-Paged Pool). Http.Sys will buffer up to - // Math.Min(16 MB, current TCP window size) - flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA; - } - - m_OutputStream.InternalHttpContext.EnsureBoundHandle(); - uint bytesSent; - statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody2( - m_OutputStream.InternalHttpContext.RequestQueueHandle, - m_OutputStream.InternalHttpContext.RequestId, - (uint)flags, - eventArgs.EntityChunkCount, - eventArgs.EntityChunks, - out bytesSent, - SafeLocalFree.Zero, - 0, - eventArgs.NativeOverlapped, - IntPtr.Zero); - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) - { - throw new HttpListenerException((int)statusCode); - } - else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - HttpListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously - callback won't be called to signal completion. - eventArgs.FinishOperationSuccess((int)bytesSent, true); - completedAsynchronously = false; - } - else - { - completedAsynchronously = true; - } - } - catch (Exception e) - { - m_WriteEventArgs.FinishOperationFailure(e, true); - m_OutputStream.SetClosedFlag(); - m_OutputStream.InternalHttpContext.Abort(); - - throw; - } - finally - { - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.WriteAsyncFast, completedAsynchronously); - } - } - - return completedAsynchronously; - } - - public override void WriteByte(byte value) - { - m_OutputStream.WriteByte(value); - } - - public override IAsyncResult BeginWrite(byte[] buffer, - int offset, - int count, - AsyncCallback callback, - object state) - { - return m_OutputStream.BeginWrite(buffer, offset, count, callback, state); - } - - public override void EndWrite(IAsyncResult asyncResult) - { - m_OutputStream.EndWrite(asyncResult); - } - - public override void Flush() - { - m_OutputStream.Flush(); - } - - public override Task FlushAsync(CancellationToken cancellationToken) - { - return m_OutputStream.FlushAsync(cancellationToken); - } - - 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 async Task CloseNetworkConnectionAsync(CancellationToken cancellationToken) - { - // need to yield here to make sure that we don't get any exception synchronously - await Task.Yield(); - - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, this, Methods.CloseNetworkConnectionAsync, string.Empty); - } - - CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration(); - - try - { - if (cancellationToken.CanBeCanceled) - { - cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false); - } -#if DEBUG - // When using fast path only one outstanding read is permitted. By switching into opaque mode - // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition) - // caller takes responsibility for enforcing this constraint. - Contract.Assert(Interlocked.Increment(ref m_OutstandingOperations.m_Writes) == 1, - "Only one outstanding write allowed at any given time."); -#endif - m_WriteTaskCompletionSource = new TaskCompletionSource(); - m_WriteEventArgs.SetShouldCloseOutput(); - if (WriteAsyncFast(m_WriteEventArgs)) - { - await m_WriteTaskCompletionSource.Task.SuppressContextFlow(); - } - } - catch (Exception error) - { - if (!s_CanHandleException(error)) - { - throw; - } - - // throw OperationCanceledException when canceled by the caller - // otherwise swallow the exception - cancellationToken.ThrowIfCancellationRequested(); - } - finally - { - cancellationTokenRegistration.Dispose(); - - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.CloseNetworkConnectionAsync, string.Empty); - } - } - } - - protected override void Dispose(bool disposing) - { - if (disposing && Interlocked.Exchange(ref m_CleanedUp, 1) == 0) - { - if (m_ReadTaskCompletionSource != null) - { - m_ReadTaskCompletionSource.TrySetCanceled(); - } - - if (m_WriteTaskCompletionSource != null) - { - m_WriteTaskCompletionSource.TrySetCanceled(); - } - - if (m_ReadEventArgs != null) - { - m_ReadEventArgs.Dispose(); - } - - if (m_WriteEventArgs != null) - { - m_WriteEventArgs.Dispose(); - } - - try - { - m_InputStream.Close(); - } - finally - { - m_OutputStream.Close(); - } - } - } - - public void Abort() - { - OnCancel(this); - } - - private static bool CanHandleException(Exception error) - { - return error is HttpListenerException || - error is ObjectDisposedException || - error is IOException; - } - - private static void OnCancel(object state) - { - Contract.Assert(state != null, "'state' MUST NOT be NULL."); - WebSocketHttpListenerDuplexStream thisPtr = state as WebSocketHttpListenerDuplexStream; - Contract.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL."); - - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, state, Methods.OnCancel, string.Empty); - } - - try - { - thisPtr.m_OutputStream.SetClosedFlag(); - // thisPtr.m_Context.Abort(); - } - catch { } - - TaskCompletionSource readTaskCompletionSourceSnapshot = thisPtr.m_ReadTaskCompletionSource; - - if (readTaskCompletionSourceSnapshot != null) - { - readTaskCompletionSourceSnapshot.TrySetCanceled(); - } - - TaskCompletionSource writeTaskCompletionSourceSnapshot = thisPtr.m_WriteTaskCompletionSource; - - if (writeTaskCompletionSourceSnapshot != null) - { - writeTaskCompletionSourceSnapshot.TrySetCanceled(); - } - - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, state, Methods.OnCancel, string.Empty); - } - } - - public void SwitchToOpaqueMode(WebSocketBase webSocket) - { - Contract.Assert(webSocket != null, "'webSocket' MUST NOT be NULL."); - Contract.Assert(m_OutputStream != null, "'m_OutputStream' MUST NOT be NULL."); - Contract.Assert(m_OutputStream.InternalHttpContext != null, - "'m_OutputStream.InternalHttpContext' MUST NOT be NULL."); - Contract.Assert(m_OutputStream.InternalHttpContext.Response != null, - "'m_OutputStream.InternalHttpContext.Response' MUST NOT be NULL."); - Contract.Assert(m_OutputStream.InternalHttpContext.Response.SentHeaders, - "Headers MUST have been sent at this point."); - Contract.Assert(!m_InOpaqueMode, "SwitchToOpaqueMode MUST NOT be called multiple times."); - - if (m_InOpaqueMode) - { - throw new InvalidOperationException(); - } - - m_WebSocket = webSocket; - m_InOpaqueMode = true; - m_ReadEventArgs = new HttpListenerAsyncEventArgs(webSocket, this); - m_ReadEventArgs.Completed += s_OnReadCompleted; - m_WriteEventArgs = new HttpListenerAsyncEventArgs(webSocket, this); - m_WriteEventArgs.Completed += s_OnWriteCompleted; - - if (WebSocketBase.LoggingEnabled) - { - Logging.Associate(Logging.WebSockets, this, webSocket); - } - } - - private static void OnWriteCompleted(object sender, HttpListenerAsyncEventArgs eventArgs) - { - Contract.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL."); - WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream; - Contract.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL."); -#if DEBUG - Contract.Assert(Interlocked.Decrement(ref thisPtr.m_OutstandingOperations.m_Writes) >= 0, - "'thisPtr.m_OutstandingOperations.m_Writes' MUST NOT be negative."); -#endif - - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, thisPtr, Methods.OnWriteCompleted, string.Empty); - } - - if (eventArgs.Exception != null) - { - thisPtr.m_WriteTaskCompletionSource.TrySetException(eventArgs.Exception); - } - else - { - thisPtr.m_WriteTaskCompletionSource.TrySetResult(null); - } - - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, thisPtr, Methods.OnWriteCompleted, string.Empty); - } - } - - private static void OnReadCompleted(object sender, HttpListenerAsyncEventArgs eventArgs) - { - Contract.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL."); - WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream; - Contract.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL."); -#if DEBUG - Contract.Assert(Interlocked.Decrement(ref thisPtr.m_OutstandingOperations.m_Reads) >= 0, - "'thisPtr.m_OutstandingOperations.m_Reads' MUST NOT be negative."); -#endif - - if (WebSocketBase.LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, thisPtr, Methods.OnReadCompleted, string.Empty); - } - - if (eventArgs.Exception != null) - { - thisPtr.m_ReadTaskCompletionSource.TrySetException(eventArgs.Exception); - } - else - { - thisPtr.m_ReadTaskCompletionSource.TrySetResult(eventArgs.BytesTransferred); - } - - if (WebSocketBase.LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, thisPtr, Methods.OnReadCompleted, string.Empty); - } - } - - internal class HttpListenerAsyncEventArgs : EventArgs, IDisposable - { - private const int Free = 0; - private const int InProgress = 1; - private const int Disposed = 2; - private int m_Operating; - - private bool m_DisposeCalled; - private SafeNativeOverlapped m_PtrNativeOverlapped; - private Overlapped m_Overlapped; - private event EventHandler m_Completed; - private byte[] m_Buffer; - private IList> m_BufferList; - private int m_Count; - private int m_Offset; - private int m_BytesTransferred; - private HttpListenerAsyncOperation m_CompletedOperation; - private UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[] m_DataChunks; - private GCHandle m_DataChunksGCHandle; - private ushort m_DataChunkCount; - private Exception m_Exception; - private bool m_ShouldCloseOutput; - private readonly WebSocketBase m_WebSocket; - private readonly WebSocketHttpListenerDuplexStream m_CurrentStream; - - public HttpListenerAsyncEventArgs(WebSocketBase webSocket, WebSocketHttpListenerDuplexStream stream) - : base() - { - m_WebSocket = webSocket; - m_CurrentStream = stream; - InitializeOverlapped(); - } - - public int BytesTransferred - { - get { return m_BytesTransferred; } - } - - public byte[] Buffer - { - get { return m_Buffer; } - } - - // BufferList property. - // Mutually exclusive with Buffer. - // Setting this property with an existing non-null Buffer will cause an assert. - public IList> BufferList - { - get { return m_BufferList; } - set - { - Contract.Assert(!m_ShouldCloseOutput, "'m_ShouldCloseOutput' MUST be 'false' at this point."); - Contract.Assert(value == null || m_Buffer == null, - "Either 'm_Buffer' or 'm_BufferList' MUST be NULL."); - Contract.Assert(m_Operating == Free, - "This property can only be modified if no IO operation is outstanding."); - Contract.Assert(value == null || value.Count == 2, - "This list can only be 'NULL' or MUST have exactly '2' items."); - m_BufferList = value; - } - } - - public bool ShouldCloseOutput - { - get { return m_ShouldCloseOutput; } - } - - public int Offset - { - get { return m_Offset; } - } - - public int Count - { - get { return m_Count; } - } - - public Exception Exception - { - get { return m_Exception; } - } - - public ushort EntityChunkCount - { - get - { - if (m_DataChunks == null) - { - return 0; - } - - return m_DataChunkCount; - } - } - - public SafeNativeOverlapped NativeOverlapped - { - get { return m_PtrNativeOverlapped; } - } - - public IntPtr EntityChunks - { - get - { - if (m_DataChunks == null) - { - return IntPtr.Zero; - } - - return Marshal.UnsafeAddrOfPinnedArrayElement(m_DataChunks, 0); - } - } - - public WebSocketHttpListenerDuplexStream CurrentStream - { - get { return m_CurrentStream; } - } - - public event EventHandler Completed - { - add - { - m_Completed += value; - } - remove - { - m_Completed -= value; - } - } - - protected virtual void OnCompleted(HttpListenerAsyncEventArgs e) - { - EventHandler handler = m_Completed; - if (handler != null) - { - handler(e.m_CurrentStream, e); - } - } - - public void SetShouldCloseOutput() - { - m_BufferList = null; - m_Buffer = null; - m_ShouldCloseOutput = true; - } - - public void Dispose() - { - // Remember that Dispose was called. - m_DisposeCalled = true; - - // Check if this object is in-use for an async socket operation. - if (Interlocked.CompareExchange(ref m_Operating, Disposed, Free) != Free) - { - // Either already disposed or will be disposed when current operation completes. - return; - } - - // OK to dispose now. - // Free native overlapped data. - FreeOverlapped(false); - - // Don't bother finalizing later. - GC.SuppressFinalize(this); - } - - // Finalizer - ~HttpListenerAsyncEventArgs() - { - FreeOverlapped(true); - } - - private unsafe void InitializeOverlapped() - { - m_Overlapped = new Overlapped(); - m_PtrNativeOverlapped = new SafeNativeOverlapped(m_Overlapped.UnsafePack(CompletionPortCallback, null)); - } - - // Method to clean up any existing Overlapped object and related state variables. - private void FreeOverlapped(bool checkForShutdown) - { - if (!checkForShutdown || !NclUtilities.HasShutdownStarted) - { - // Free the overlapped object - if (m_PtrNativeOverlapped != null && !m_PtrNativeOverlapped.IsInvalid) - { - m_PtrNativeOverlapped.Dispose(); - } - - if (m_DataChunksGCHandle.IsAllocated) - { - m_DataChunksGCHandle.Free(); - } - } - } - - // Method called to prepare for a native async http.sys call. - // This method performs the tasks common to all http.sys operations. - internal void StartOperationCommon(WebSocketHttpListenerDuplexStream currentStream) - { - // Change status to "in-use". - if(Interlocked.CompareExchange(ref m_Operating, InProgress, Free) != Free) - { - // If it was already "in-use" check if Dispose was called. - if (m_DisposeCalled) - { - // Dispose was called - throw ObjectDisposed. - throw new ObjectDisposedException(GetType().FullName); - } - - Contract.Assert(false, "Only one outstanding async operation is allowed per HttpListenerAsyncEventArgs instance."); - // Only one at a time. - throw new InvalidOperationException(); - } - - // HttpSendResponseEntityBody can return ERROR_INVALID_PARAMETER if the InternalHigh field of the overlapped - // is not IntPtr.Zero, so we have to reset this field because we are reusing the Overlapped. - // When using the IAsyncResult based approach of HttpListenerResponseStream the Overlapped is reinitialized - // for each operation by the CLR when returned from the OverlappedDataCache. - NativeOverlapped.ReinitializeNativeOverlapped(); - m_Exception = null; - m_BytesTransferred = 0; - } - - internal void StartOperationReceive() - { - // Remember the operation type. - m_CompletedOperation = HttpListenerAsyncOperation.Receive; - } - - internal void StartOperationSend() - { - UpdateDataChunk(); - - // Remember the operation type. - m_CompletedOperation = HttpListenerAsyncOperation.Send; - } - - public void SetBuffer(byte[] buffer, int offset, int count) - { - Contract.Assert(!m_ShouldCloseOutput, "'m_ShouldCloseOutput' MUST be 'false' at this point."); - Contract.Assert(buffer == null || m_BufferList == null, "Either 'm_Buffer' or 'm_BufferList' MUST be NULL."); - m_Buffer = buffer; - m_Offset = offset; - m_Count = count; - } - - private unsafe void UpdateDataChunk() - { - if (m_DataChunks == null) - { - m_DataChunks = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[2]; - m_DataChunksGCHandle = GCHandle.Alloc(m_DataChunks); - m_DataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - m_DataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - m_DataChunks[1] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); - m_DataChunks[1].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; - } - - Contract.Assert(m_Buffer == null || m_BufferList == null, "Either 'm_Buffer' or 'm_BufferList' MUST be NULL."); - Contract.Assert(m_ShouldCloseOutput || m_Buffer != null || m_BufferList != null, "Either 'm_Buffer' or 'm_BufferList' MUST NOT be NULL."); - - // The underlying byte[] m_Buffer or each m_BufferList[].Array are pinned already - if (m_Buffer != null) - { - UpdateDataChunk(0, m_Buffer, m_Offset, m_Count); - UpdateDataChunk(1, null, 0, 0); - m_DataChunkCount = 1; - } - else if (m_BufferList != null) - { - Contract.Assert(m_BufferList != null && m_BufferList.Count == 2, - "'m_BufferList' MUST NOT be NULL and have exactly '2' items at this point."); - UpdateDataChunk(0, m_BufferList[0].Array, m_BufferList[0].Offset, m_BufferList[0].Count); - UpdateDataChunk(1, m_BufferList[1].Array, m_BufferList[1].Offset, m_BufferList[1].Count); - m_DataChunkCount = 2; - } - else - { - Contract.Assert(m_ShouldCloseOutput, "'m_ShouldCloseOutput' MUST be 'true' at this point."); - m_DataChunks = null; - } - } - - private unsafe void UpdateDataChunk(int index, byte[] buffer, int offset, int count) - { - if (buffer == null) - { - m_DataChunks[index].pBuffer = null; - m_DataChunks[index].BufferLength = 0; - return; - } - - if (m_WebSocket.InternalBuffer.IsInternalBuffer(buffer, offset, count)) - { - m_DataChunks[index].pBuffer = (byte*)(m_WebSocket.InternalBuffer.ToIntPtr(offset)); - } - else - { - m_DataChunks[index].pBuffer = - (byte*)m_WebSocket.InternalBuffer.ConvertPinnedSendPayloadToNative(buffer, offset, count); - } - - m_DataChunks[index].BufferLength = (uint)count; - } - - // Method to mark this object as no longer "in-use". - // Will also execute a Dispose deferred because I/O was in progress. - internal void Complete() - { - // Mark as not in-use - m_Operating = Free; - - // Check for deferred Dispose(). - // The deferred Dispose is not guaranteed if Dispose is called while an operation is in progress. - // The m_DisposeCalled variable is not managed in a thread-safe manner on purpose for performance. - if (m_DisposeCalled) - { - Dispose(); - } - } - - // Method to update internal state after sync or async completion. - private void SetResults(Exception exception, int bytesTransferred) - { - m_Exception = exception; - m_BytesTransferred = bytesTransferred; - } - - internal void FinishOperationFailure(Exception exception, bool syncCompletion) - { - SetResults(exception, 0); - - if (WebSocketBase.LoggingEnabled) - { - Logging.PrintError(Logging.WebSockets, m_CurrentStream, - m_CompletedOperation == HttpListenerAsyncOperation.Receive ? Methods.ReadAsyncFast : Methods.WriteAsyncFast, - exception.ToString()); - } - - Complete(); - OnCompleted(this); - } - - internal void FinishOperationSuccess(int bytesTransferred, bool syncCompletion) - { - SetResults(null, bytesTransferred); - - if (WebSocketBase.LoggingEnabled) - { - if (m_Buffer != null) - { - Logging.Dump(Logging.WebSockets, m_CurrentStream, - m_CompletedOperation == HttpListenerAsyncOperation.Receive ? Methods.ReadAsyncFast : Methods.WriteAsyncFast, - m_Buffer, m_Offset, bytesTransferred); - } - else if (m_BufferList != null) - { - Contract.Assert(m_CompletedOperation == HttpListenerAsyncOperation.Send, - "'BufferList' is only supported for send operations."); - - foreach (ArraySegment buffer in BufferList) - { - Logging.Dump(Logging.WebSockets, this, Methods.WriteAsyncFast, buffer.Array, buffer.Offset, buffer.Count); - } - } - else - { - Logging.PrintLine(Logging.WebSockets, TraceEventType.Verbose, 0, - string.Format(CultureInfo.InvariantCulture, "Output channel closed for {0}#{1}", - m_CurrentStream.GetType().Name, ValidationHelper.HashString(m_CurrentStream))); - } - } - - if (m_ShouldCloseOutput) - { - m_CurrentStream.m_OutputStream.SetClosedFlag(); - } - - // Complete the operation and raise completion event. - Complete(); - OnCompleted(this); - } - - private unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) - { - if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS || - errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) - { - FinishOperationSuccess((int)numBytes, false); - } - else - { - FinishOperationFailure(new HttpListenerException((int)errorCode), false); - } - } - - public enum HttpListenerAsyncOperation - { - None, - Receive, - Send - } - } - - private static class Methods - { - public const string CloseNetworkConnectionAsync = "CloseNetworkConnectionAsync"; - public const string OnCancel = "OnCancel"; - public const string OnReadCompleted = "OnReadCompleted"; - public const string OnWriteCompleted = "OnWriteCompleted"; - public const string ReadAsyncFast = "ReadAsyncFast"; - public const string ReadAsyncCore = "ReadAsyncCore"; - public const string WriteAsyncFast = "WriteAsyncFast"; - public const string WriteAsyncCore = "WriteAsyncCore"; - public const string MultipleWriteAsyncCore = "MultipleWriteAsyncCore"; - } - } -} -*/ \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj b/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj deleted file mode 100644 index a5fa974e8a..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/Microsoft.Net.WebSockets.Server.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - e788aeae-2cb4-4bfa-8746-d0bb7e93a1bb - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeLoadLibrary.cs deleted file mode 100644 index dcb231e78b..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeLoadLibrary.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.Net.WebSockets -{ - internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid - { - private const string KERNEL32 = "kernel32.dll"; - - public static readonly SafeLoadLibrary Zero = new SafeLoadLibrary(false); - - private SafeLoadLibrary() : base(true) - { - } - - private SafeLoadLibrary(bool ownsHandle) : base(ownsHandle) - { - } - - public static unsafe SafeLoadLibrary LoadLibraryEx(string library) - { - SafeLoadLibrary result = UnsafeNativeMethods.SafeNetHandles.LoadLibraryExW(library, null, 0); - if (result.IsInvalid) - { - result.SetHandleAsInvalid(); - } - return result; - } - - protected override bool ReleaseHandle() - { - return UnsafeNativeMethods.SafeNetHandles.FreeLibrary(handle); - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeWebSocketHandle.cs b/src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeWebSocketHandle.cs deleted file mode 100644 index 1219624f00..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/NativeInterop/SafeWebSocketHandle.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.Net.WebSockets -{ - // This class is a wrapper for a WSPC (WebSocket protocol component) session. WebSocketCreateClientHandle and WebSocketCreateServerHandle return a PVOID and not a real handle - // but we use a SafeHandle because it provides us the guarantee that WebSocketDeleteHandle will always get called. - internal sealed class SafeWebSocketHandle : SafeHandleZeroOrMinusOneIsInvalid - { - internal SafeWebSocketHandle() - : base(true) - { - } - - protected override bool ReleaseHandle() - { - if (this.IsInvalid) - { - return true; - } - - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketDeleteHandle(this.handle); - return true; - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs deleted file mode 100644 index 43c86e1fa2..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/NativeInterop/UnsafeNativeMethods.cs +++ /dev/null @@ -1,875 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics.Contracts; -using System.IO; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Microsoft.Net.WebSockets -{ - internal static class UnsafeNativeMethods - { -#if NETSTANDARD1_3 - private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll"; -#else - private const string KERNEL32 = "kernel32.dll"; -#endif - private const string WEBSOCKET = "websocket.dll"; - - internal static class SafeNetHandles - { -#if NETSTANDARD1_3 - [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, CharSet=CharSet.Unicode, SetLastError = true)] -#endif - internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); - -#if NETSTANDARD1_3 - [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif - internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); - } - - internal static class WebSocketProtocolComponent - { - private static readonly string DllFileName; - private static readonly string DummyWebsocketKeyBase64 = Convert.ToBase64String(new byte[16]); - private static readonly SafeLoadLibrary WebSocketDllHandle; - private static readonly string PrivateSupportedVersion; - - private static readonly HttpHeader[] InitialClientRequestHeaders = new HttpHeader[] - { - new HttpHeader() - { - Name = HttpKnownHeaderNames.Connection, - NameLength = (uint)HttpKnownHeaderNames.Connection.Length, - Value = HttpKnownHeaderNames.Upgrade, - ValueLength = (uint)HttpKnownHeaderNames.Upgrade.Length - }, - new HttpHeader() - { - Name = HttpKnownHeaderNames.Upgrade, - NameLength = (uint)HttpKnownHeaderNames.Upgrade.Length, - Value = WebSocketHelpers.WebSocketUpgradeToken, - ValueLength = (uint)WebSocketHelpers.WebSocketUpgradeToken.Length - } - }; - - private static readonly HttpHeader[] ServerFakeRequestHeaders; - - internal static class Errors - { - internal const int E_INVALID_OPERATION = unchecked((int)0x80000050); - internal const int E_INVALID_PROTOCOL_OPERATION = unchecked((int)0x80000051); - internal const int E_INVALID_PROTOCOL_FORMAT = unchecked((int)0x80000052); - internal const int E_NUMERIC_OVERFLOW = unchecked((int)0x80000053); - internal const int E_FAIL = unchecked((int)0x80004005); - } - - internal enum Action - { - NoAction = 0, - SendToNetwork = 1, - IndicateSendComplete = 2, - ReceiveFromNetwork = 3, - IndicateReceiveComplete = 4, - } - - internal enum BufferType : uint - { - None = 0x00000000, - UTF8Message = 0x80000000, - UTF8Fragment = 0x80000001, - BinaryMessage = 0x80000002, - BinaryFragment = 0x80000003, - Close = 0x80000004, - PingPong = 0x80000005, - UnsolicitedPong = 0x80000006 - } - - internal enum PropertyType - { - ReceiveBufferSize = 0, - SendBufferSize = 1, - DisableMasking = 2, - AllocatedBuffer = 3, - DisableUtf8Verification = 4, - KeepAliveInterval = 5, - } - - internal enum ActionQueue - { - Send = 1, - Receive = 2, - } - - [StructLayout(LayoutKind.Sequential)] - internal struct Property - { - internal PropertyType Type; - internal IntPtr PropertyData; - internal uint PropertySize; - } - - [StructLayout(LayoutKind.Explicit)] - internal struct Buffer - { - [FieldOffset(0)] - internal DataBuffer Data; - [FieldOffset(0)] - internal CloseBuffer CloseStatus; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct DataBuffer - { - internal IntPtr BufferData; - internal uint BufferLength; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct CloseBuffer - { - internal IntPtr ReasonData; - internal uint ReasonLength; - internal ushort CloseStatus; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HttpHeader - { - [MarshalAs(UnmanagedType.LPStr)] - internal string Name; - internal uint NameLength; - [MarshalAs(UnmanagedType.LPStr)] - internal string Value; - internal uint ValueLength; - } - - static WebSocketProtocolComponent() - { -#if NETSTANDARD1_3 - DllFileName = Path.Combine(Environment.GetEnvironmentVariable("SYSTEMROOT"), "System32", WEBSOCKET); -#else - DllFileName = Path.Combine(Environment.SystemDirectory, WEBSOCKET); -#endif - WebSocketDllHandle = SafeLoadLibrary.LoadLibraryEx(DllFileName); - - if (!WebSocketDllHandle.IsInvalid) - { - PrivateSupportedVersion = GetSupportedVersion(); - - ServerFakeRequestHeaders = new HttpHeader[] - { - new HttpHeader() - { - Name = HttpKnownHeaderNames.Connection, - NameLength = (uint)HttpKnownHeaderNames.Connection.Length, - Value = HttpKnownHeaderNames.Upgrade, - ValueLength = (uint)HttpKnownHeaderNames.Upgrade.Length - }, - new HttpHeader() - { - Name = HttpKnownHeaderNames.Upgrade, - NameLength = (uint)HttpKnownHeaderNames.Upgrade.Length, - Value = WebSocketHelpers.WebSocketUpgradeToken, - ValueLength = (uint)WebSocketHelpers.WebSocketUpgradeToken.Length - }, - new HttpHeader() - { - Name = HttpKnownHeaderNames.Host, - NameLength = (uint)HttpKnownHeaderNames.Host.Length, - Value = string.Empty, - ValueLength = 0 - }, - new HttpHeader() - { - Name = HttpKnownHeaderNames.SecWebSocketVersion, - NameLength = (uint)HttpKnownHeaderNames.SecWebSocketVersion.Length, - Value = SupportedVersion, - ValueLength = (uint)SupportedVersion.Length - }, - new HttpHeader() - { - Name = HttpKnownHeaderNames.SecWebSocketKey, - NameLength = (uint)HttpKnownHeaderNames.SecWebSocketKey.Length, - Value = DummyWebsocketKeyBase64, - ValueLength = (uint)DummyWebsocketKeyBase64.Length - } - }; - } - } - - internal static string SupportedVersion - { - get - { - if (WebSocketDllHandle.IsInvalid) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - return PrivateSupportedVersion; - } - } - - internal static bool IsSupported - { - get - { - return !WebSocketDllHandle.IsInvalid; - } - } - - internal static string GetSupportedVersion() - { - if (WebSocketDllHandle.IsInvalid) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - SafeWebSocketHandle webSocketHandle = null; - try - { - int errorCode = WebSocketCreateClientHandle_Raw(null, 0, out webSocketHandle); - ThrowOnError(errorCode); - - if (webSocketHandle == null || - webSocketHandle.IsInvalid) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - IntPtr additionalHeadersPtr; - uint additionalHeaderCount; - - errorCode = WebSocketBeginClientHandshake_Raw(webSocketHandle, - IntPtr.Zero, - 0, - IntPtr.Zero, - 0, - InitialClientRequestHeaders, - (uint)InitialClientRequestHeaders.Length, - out additionalHeadersPtr, - out additionalHeaderCount); - ThrowOnError(errorCode); - - HttpHeader[] additionalHeaders = MarshalHttpHeaders(additionalHeadersPtr, (int)additionalHeaderCount); - - string version = null; - foreach (HttpHeader header in additionalHeaders) - { - if (string.Compare(header.Name, - HttpKnownHeaderNames.SecWebSocketVersion, - StringComparison.OrdinalIgnoreCase) == 0) - { - version = header.Value; - break; - } - } - Contract.Assert(version != null, "'version' MUST NOT be NULL."); - - return version; - } - finally - { - if (webSocketHandle != null) - { - webSocketHandle.Dispose(); - } - } - } - - internal static void WebSocketCreateClientHandle(Property[] properties, - out SafeWebSocketHandle webSocketHandle) - { - uint propertyCount = properties == null ? 0 : (uint)properties.Length; - - if (WebSocketDllHandle.IsInvalid) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - int errorCode = WebSocketCreateClientHandle_Raw(properties, propertyCount, out webSocketHandle); - ThrowOnError(errorCode); - - if (webSocketHandle == null || - webSocketHandle.IsInvalid) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - IntPtr additionalHeadersPtr; - uint additionalHeaderCount; - - // Currently the WSPC doesn't allow to initiate a data session - // without also being involved in the http handshake - // There is no information whatsoever, which is needed by the - // WSPC for parsing WebSocket frames from the HTTP handshake - // In the managed implementation the HTTP header handling - // will be done using the managed HTTP stack and we will - // just fake an HTTP handshake for the WSPC calling - // WebSocketBeginClientHandshake and WebSocketEndClientHandshake - // with statically defined dummy headers. - errorCode = WebSocketBeginClientHandshake_Raw(webSocketHandle, - IntPtr.Zero, - 0, - IntPtr.Zero, - 0, - InitialClientRequestHeaders, - (uint)InitialClientRequestHeaders.Length, - out additionalHeadersPtr, - out additionalHeaderCount); - - ThrowOnError(errorCode); - - HttpHeader[] additionalHeaders = MarshalHttpHeaders(additionalHeadersPtr, (int)additionalHeaderCount); - - string key = null; - foreach (HttpHeader header in additionalHeaders) - { - if (string.Compare(header.Name, - HttpKnownHeaderNames.SecWebSocketKey, - StringComparison.OrdinalIgnoreCase) == 0) - { - key = header.Value; - break; - } - } - Contract.Assert(key != null, "'key' MUST NOT be NULL."); - - string acceptValue = WebSocketHelpers.GetSecWebSocketAcceptString(key); - HttpHeader[] responseHeaders = new HttpHeader[] - { - new HttpHeader() - { - Name = HttpKnownHeaderNames.Connection, - NameLength = (uint)HttpKnownHeaderNames.Connection.Length, - Value = HttpKnownHeaderNames.Upgrade, - ValueLength = (uint)HttpKnownHeaderNames.Upgrade.Length - }, - new HttpHeader() - { - Name = HttpKnownHeaderNames.Upgrade, - NameLength = (uint)HttpKnownHeaderNames.Upgrade.Length, - Value = WebSocketHelpers.WebSocketUpgradeToken, - ValueLength = (uint)WebSocketHelpers.WebSocketUpgradeToken.Length - }, - new HttpHeader() - { - Name = HttpKnownHeaderNames.SecWebSocketAccept, - NameLength = (uint)HttpKnownHeaderNames.SecWebSocketAccept.Length, - Value = acceptValue, - ValueLength = (uint)acceptValue.Length - } - }; - - errorCode = WebSocketEndClientHandshake_Raw(webSocketHandle, - responseHeaders, - (uint)responseHeaders.Length, - IntPtr.Zero, - IntPtr.Zero, - IntPtr.Zero); - - ThrowOnError(errorCode); - - Contract.Assert(webSocketHandle != null, "'webSocketHandle' MUST NOT be NULL at this point."); - } - - internal static void WebSocketCreateServerHandle(Property[] properties, - int propertyCount, - out SafeWebSocketHandle webSocketHandle) - { - Contract.Assert(propertyCount >= 0, "'propertyCount' MUST NOT be negative."); - Contract.Assert((properties == null && propertyCount == 0) || - (properties != null && propertyCount == properties.Length), - "'propertyCount' MUST MATCH 'properties.Length'."); - - if (WebSocketDllHandle.IsInvalid) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - int errorCode = WebSocketCreateServerHandle_Raw(properties, (uint)propertyCount, out webSocketHandle); - ThrowOnError(errorCode); - - if (webSocketHandle == null || - webSocketHandle.IsInvalid) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - IntPtr responseHeadersPtr; - uint responseHeaderCount; - - // Currently the WSPC doesn't allow to initiate a data session - // without also being involved in the http handshake - // There is no information whatsoever, which is needed by the - // WSPC for parsing WebSocket frames from the HTTP handshake - // In the managed implementation the HTTP header handling - // will be done using the managed HTTP stack and we will - // just fake an HTTP handshake for the WSPC calling - // WebSocketBeginServerHandshake and WebSocketEndServerHandshake - // with statically defined dummy headers. - errorCode = WebSocketBeginServerHandshake_Raw(webSocketHandle, - IntPtr.Zero, - IntPtr.Zero, - 0, - ServerFakeRequestHeaders, - (uint)ServerFakeRequestHeaders.Length, - out responseHeadersPtr, - out responseHeaderCount); - - ThrowOnError(errorCode); - - HttpHeader[] responseHeaders = MarshalHttpHeaders(responseHeadersPtr, (int)responseHeaderCount); - errorCode = WebSocketEndServerHandshake_Raw(webSocketHandle); - - ThrowOnError(errorCode); - - Contract.Assert(webSocketHandle != null, "'webSocketHandle' MUST NOT be NULL at this point."); - } - - internal static void WebSocketAbortHandle(SafeHandle webSocketHandle) - { - Contract.Assert(webSocketHandle != null && !webSocketHandle.IsInvalid, - "'webSocketHandle' MUST NOT be NULL or INVALID."); - - WebSocketAbortHandle_Raw(webSocketHandle); - - DrainActionQueue(webSocketHandle, ActionQueue.Send); - DrainActionQueue(webSocketHandle, ActionQueue.Receive); - } - - internal static void WebSocketDeleteHandle(IntPtr webSocketPtr) - { - Contract.Assert(webSocketPtr != IntPtr.Zero, "'webSocketPtr' MUST NOT be IntPtr.Zero."); - WebSocketDeleteHandle_Raw(webSocketPtr); - } - - internal static void WebSocketSend(WebSocketBase webSocket, - BufferType bufferType, - Buffer buffer) - { - Contract.Assert(webSocket != null, - "'webSocket' MUST NOT be NULL or INVALID."); - Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, - "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); - - ThrowIfSessionHandleClosed(webSocket); - - int errorCode; - try - { - errorCode = WebSocketSend_Raw(webSocket.SessionHandle, bufferType, ref buffer, IntPtr.Zero); - } - catch (ObjectDisposedException innerException) - { - throw ConvertObjectDisposedException(webSocket, innerException); - } - - ThrowOnError(errorCode); - } - - internal static void WebSocketSendWithoutBody(WebSocketBase webSocket, - BufferType bufferType) - { - Contract.Assert(webSocket != null, - "'webSocket' MUST NOT be NULL or INVALID."); - Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, - "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); - - ThrowIfSessionHandleClosed(webSocket); - - int errorCode; - try - { - errorCode = WebSocketSendWithoutBody_Raw(webSocket.SessionHandle, bufferType, IntPtr.Zero, IntPtr.Zero); - } - catch (ObjectDisposedException innerException) - { - throw ConvertObjectDisposedException(webSocket, innerException); - } - - ThrowOnError(errorCode); - } - - internal static void WebSocketReceive(WebSocketBase webSocket) - { - Contract.Assert(webSocket != null, - "'webSocket' MUST NOT be NULL or INVALID."); - Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, - "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); - - ThrowIfSessionHandleClosed(webSocket); - - int errorCode; - try - { - errorCode = WebSocketReceive_Raw(webSocket.SessionHandle, IntPtr.Zero, IntPtr.Zero); - } - catch (ObjectDisposedException innerException) - { - throw ConvertObjectDisposedException(webSocket, innerException); - } - - ThrowOnError(errorCode); - } - - internal static void WebSocketGetAction(WebSocketBase webSocket, - ActionQueue actionQueue, - Buffer[] dataBuffers, - ref uint dataBufferCount, - out Action action, - out BufferType bufferType, - out IntPtr actionContext) - { - Contract.Assert(webSocket != null, - "'webSocket' MUST NOT be NULL or INVALID."); - Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, - "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); - Contract.Assert(dataBufferCount >= 0, "'dataBufferCount' MUST NOT be negative."); - Contract.Assert((dataBuffers == null && dataBufferCount == 0) || - (dataBuffers != null && dataBufferCount == dataBuffers.Length), - "'dataBufferCount' MUST MATCH 'dataBuffers.Length'."); - - action = Action.NoAction; - bufferType = BufferType.None; - actionContext = IntPtr.Zero; - - IntPtr dummy; - ThrowIfSessionHandleClosed(webSocket); - - int errorCode; - try - { - errorCode = WebSocketGetAction_Raw(webSocket.SessionHandle, - actionQueue, - dataBuffers, - ref dataBufferCount, - out action, - out bufferType, - out dummy, - out actionContext); - } - catch (ObjectDisposedException innerException) - { - throw ConvertObjectDisposedException(webSocket, innerException); - } - ThrowOnError(errorCode); - - webSocket.ValidateNativeBuffers(action, bufferType, dataBuffers, dataBufferCount); - - Contract.Assert(dataBufferCount >= 0); - Contract.Assert((dataBufferCount == 0 && dataBuffers == null) || - (dataBufferCount <= dataBuffers.Length)); - } - - internal static void WebSocketCompleteAction(WebSocketBase webSocket, - IntPtr actionContext, - int bytesTransferred) - { - Contract.Assert(webSocket != null, - "'webSocket' MUST NOT be NULL or INVALID."); - Contract.Assert(webSocket.SessionHandle != null && !webSocket.SessionHandle.IsInvalid, - "'webSocket.SessionHandle' MUST NOT be NULL or INVALID."); - Contract.Assert(actionContext != IntPtr.Zero, "'actionContext' MUST NOT be IntPtr.Zero."); - Contract.Assert(bytesTransferred >= 0, "'bytesTransferred' MUST NOT be negative."); - - if (webSocket.SessionHandle.IsClosed) - { - return; - } - - try - { - WebSocketCompleteAction_Raw(webSocket.SessionHandle, actionContext, (uint)bytesTransferred); - } - catch (ObjectDisposedException) - { - } - } - - internal static TimeSpan WebSocketGetDefaultKeepAliveInterval() - { - uint result = 0; - uint size = sizeof(uint); - int errorCode = WebSocketGetGlobalProperty_Raw(PropertyType.KeepAliveInterval, ref result, ref size); - if (!Succeeded(errorCode)) - { - Contract.Assert(errorCode == 0, "errorCode: " + errorCode); - return Timeout.InfiniteTimeSpan; - } - return TimeSpan.FromMilliseconds(result); - } - - private static void DrainActionQueue(SafeHandle webSocketHandle, ActionQueue actionQueue) - { - Contract.Assert(webSocketHandle != null && !webSocketHandle.IsInvalid, - "'webSocketHandle' MUST NOT be NULL or INVALID."); - - IntPtr actionContext; - IntPtr dummy; - Action action; - BufferType bufferType; - - while (true) - { - Buffer[] dataBuffers = new Buffer[1]; - uint dataBufferCount = 1; - int errorCode = WebSocketGetAction_Raw(webSocketHandle, - actionQueue, - dataBuffers, - ref dataBufferCount, - out action, - out bufferType, - out dummy, - out actionContext); - - if (!Succeeded(errorCode)) - { - Contract.Assert(errorCode == 0, "'errorCode' MUST be 0."); - return; - } - - if (action == Action.NoAction) - { - return; - } - - WebSocketCompleteAction_Raw(webSocketHandle, actionContext, 0); - } - } - - private static void MarshalAndVerifyHttpHeader(IntPtr httpHeaderPtr, - ref HttpHeader httpHeader) - { - Contract.Assert(httpHeaderPtr != IntPtr.Zero, "'currentHttpHeaderPtr' MUST NOT be IntPtr.Zero."); - - IntPtr httpHeaderNamePtr = Marshal.ReadIntPtr(httpHeaderPtr); - IntPtr lengthPtr = IntPtr.Add(httpHeaderPtr, IntPtr.Size); - int length = Marshal.ReadInt32(lengthPtr); - Contract.Assert(length >= 0, "'length' MUST NOT be negative."); - - if (httpHeaderNamePtr != IntPtr.Zero) - { - httpHeader.Name = Marshal.PtrToStringAnsi(httpHeaderNamePtr, length); - } - - if ((httpHeader.Name == null && length != 0) || - (httpHeader.Name != null && length != httpHeader.Name.Length)) - { - Contract.Assert(false, "The length of 'httpHeader.Name' MUST MATCH 'length'."); - throw new AccessViolationException(); - } - - // structure of HttpHeader: - // Name = string* - // NameLength = uint* - // Value = string* - // ValueLength = uint* - // NOTE - All fields in the object are pointers to the actual value, hence the use of - // n * IntPtr.Size to get to the correct place in the object. - int valueOffset = 2 * IntPtr.Size; - int lengthOffset = 3 * IntPtr.Size; - - IntPtr httpHeaderValuePtr = - Marshal.ReadIntPtr(IntPtr.Add(httpHeaderPtr, valueOffset)); - lengthPtr = IntPtr.Add(httpHeaderPtr, lengthOffset); - length = Marshal.ReadInt32(lengthPtr); - httpHeader.Value = Marshal.PtrToStringAnsi(httpHeaderValuePtr, (int)length); - - if ((httpHeader.Value == null && length != 0) || - (httpHeader.Value != null && length != httpHeader.Value.Length)) - { - Contract.Assert(false, "The length of 'httpHeader.Value' MUST MATCH 'length'."); - throw new AccessViolationException(); - } - } - - private static HttpHeader[] MarshalHttpHeaders(IntPtr nativeHeadersPtr, - int nativeHeaderCount) - { - Contract.Assert(nativeHeaderCount >= 0, "'nativeHeaderCount' MUST NOT be negative."); - Contract.Assert(nativeHeadersPtr != IntPtr.Zero || nativeHeaderCount == 0, - "'nativeHeaderCount' MUST be 0."); - - HttpHeader[] httpHeaders = new HttpHeader[nativeHeaderCount]; - - // structure of HttpHeader: - // Name = string* - // NameLength = uint* - // Value = string* - // ValueLength = uint* - // NOTE - All fields in the object are pointers to the actual value, hence the use of - // 4 * IntPtr.Size to get to the next header. - int httpHeaderStructSize = 4 * IntPtr.Size; - - for (int i = 0; i < nativeHeaderCount; i++) - { - int offset = httpHeaderStructSize * i; - IntPtr currentHttpHeaderPtr = IntPtr.Add(nativeHeadersPtr, offset); - MarshalAndVerifyHttpHeader(currentHttpHeaderPtr, ref httpHeaders[i]); - } - - Contract.Assert(httpHeaders != null); - Contract.Assert(httpHeaders.Length == nativeHeaderCount); - - return httpHeaders; - } - - public static bool Succeeded(int hr) - { - return (hr >= 0); - } - - private static void ThrowOnError(int errorCode) - { - if (Succeeded(errorCode)) - { - return; - } - - throw new WebSocketException(errorCode); - } - - private static void ThrowIfSessionHandleClosed(WebSocketBase webSocket) - { - if (webSocket.SessionHandle.IsClosed) - { - throw new WebSocketException(WebSocketError.InvalidState, - SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, webSocket.GetType().FullName, webSocket.State)); - } - } - - private static WebSocketException ConvertObjectDisposedException(WebSocketBase webSocket, ObjectDisposedException innerException) - { - return new WebSocketException(WebSocketError.InvalidState, - SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, webSocket.GetType().FullName, webSocket.State), - innerException); - } - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketCreateClientHandle", ExactSpelling = true)] - private static extern int WebSocketCreateClientHandle_Raw( - [In]Property[] properties, - [In] uint propertyCount, - [Out] out SafeWebSocketHandle webSocketHandle); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketBeginClientHandshake", ExactSpelling = true)] - private static extern int WebSocketBeginClientHandshake_Raw( - [In] SafeHandle webSocketHandle, - [In] IntPtr subProtocols, - [In] uint subProtocolCount, - [In] IntPtr extensions, - [In] uint extensionCount, - [In] HttpHeader[] initialHeaders, - [In] uint initialHeaderCount, - [Out] out IntPtr additionalHeadersPtr, - [Out] out uint additionalHeaderCount); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketEndClientHandshake", ExactSpelling = true)] - private static extern int WebSocketEndClientHandshake_Raw([In] SafeHandle webSocketHandle, - [In] HttpHeader[] responseHeaders, - [In] uint responseHeaderCount, - [In, Out] IntPtr selectedExtensions, - [In] IntPtr selectedExtensionCount, - [In] IntPtr selectedSubProtocol); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketBeginServerHandshake", ExactSpelling = true)] - private static extern int WebSocketBeginServerHandshake_Raw( - [In] SafeHandle webSocketHandle, - [In] IntPtr subProtocol, - [In] IntPtr extensions, - [In] uint extensionCount, - [In] HttpHeader[] requestHeaders, - [In] uint requestHeaderCount, - [Out] out IntPtr responseHeadersPtr, - [Out] out uint responseHeaderCount); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketEndServerHandshake", ExactSpelling = true)] - private static extern int WebSocketEndServerHandshake_Raw([In] SafeHandle webSocketHandle); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketCreateServerHandle", ExactSpelling = true)] - private static extern int WebSocketCreateServerHandle_Raw( - [In]Property[] properties, - [In] uint propertyCount, - [Out] out SafeWebSocketHandle webSocketHandle); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketAbortHandle", ExactSpelling = true)] - private static extern void WebSocketAbortHandle_Raw( - [In] SafeHandle webSocketHandle); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketDeleteHandle", ExactSpelling = true)] - private static extern void WebSocketDeleteHandle_Raw( - [In] IntPtr webSocketHandle); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketSend", ExactSpelling = true)] - private static extern int WebSocketSend_Raw( - [In] SafeHandle webSocketHandle, - [In] BufferType bufferType, - [In] ref Buffer buffer, - [In] IntPtr applicationContext); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketSend", ExactSpelling = true)] - private static extern int WebSocketSendWithoutBody_Raw( - [In] SafeHandle webSocketHandle, - [In] BufferType bufferType, - [In] IntPtr buffer, - [In] IntPtr applicationContext); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketReceive", ExactSpelling = true)] - private static extern int WebSocketReceive_Raw( - [In] SafeHandle webSocketHandle, - [In] IntPtr buffers, - [In] IntPtr applicationContext); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketGetAction", ExactSpelling = true)] - private static extern int WebSocketGetAction_Raw( - [In] SafeHandle webSocketHandle, - [In] ActionQueue actionQueue, - [In, Out] Buffer[] dataBuffers, - [In, Out] ref uint dataBufferCount, - [Out] out Action action, - [Out] out BufferType bufferType, - [Out] out IntPtr applicationContext, - [Out] out IntPtr actionContext); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketCompleteAction", ExactSpelling = true)] - private static extern void WebSocketCompleteAction_Raw( - [In] SafeHandle webSocketHandle, - [In] IntPtr actionContext, - [In] uint bytesTransferred); - - [DllImport(WEBSOCKET, EntryPoint = "WebSocketGetGlobalProperty", ExactSpelling = true)] - private static extern int WebSocketGetGlobalProperty_Raw( - [In] PropertyType property, - [In, Out] ref uint value, - [In, Out] ref uint size); - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs deleted file mode 100644 index 79eeb571ef..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.Net.WebSockets.Server/ServerWebSocket.cs b/src/Microsoft.Net.WebSockets.Server/ServerWebSocket.cs deleted file mode 100644 index ebf8542848..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/ServerWebSocket.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; -using System.IO; -using System.Runtime.InteropServices; - -namespace Microsoft.Net.WebSockets -{ - internal sealed class ServerWebSocket : WebSocketBase - { - private readonly SafeHandle _sessionHandle; - private readonly UnsafeNativeMethods.WebSocketProtocolComponent.Property[] _properties; - - public ServerWebSocket(Stream innerStream, - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) - : base(innerStream, subProtocol, keepAliveInterval, - WebSocketBuffer.CreateServerBuffer(internalBuffer, receiveBufferSize)) - { - _properties = this.InternalBuffer.CreateProperties(false); - _sessionHandle = this.CreateWebSocketHandle(); - - if (_sessionHandle == null || _sessionHandle.IsInvalid) - { - WebSocketHelpers.ThrowPlatformNotSupportedException_WSPC(); - } - - StartKeepAliveTimer(); - } - - internal override SafeHandle SessionHandle - { - get - { - Contract.Assert(_sessionHandle != null, "'m_SessionHandle MUST NOT be NULL."); - return _sessionHandle; - } - } - - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", - Justification = "No arbitrary data controlled by PT code is leaking into native code.")] - private SafeHandle CreateWebSocketHandle() - { - Contract.Assert(_properties != null, "'m_Properties' MUST NOT be NULL."); - SafeWebSocketHandle sessionHandle; - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCreateServerHandle(_properties, - _properties.Length, - out sessionHandle); - Contract.Assert(sessionHandle != null, "'sessionHandle MUST NOT be NULL."); - - return sessionHandle; - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs deleted file mode 100644 index 1526acd056..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketBase.cs +++ /dev/null @@ -1,2499 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; -using System.Globalization; -using System.IO; -using System.Net.WebSockets; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Net.WebSockets -{ - internal abstract class WebSocketBase : WebSocket, IDisposable - { - // private static volatile bool s_LoggingEnabled; - - private readonly OutstandingOperationHelper _closeOutstandingOperationHelper; - private readonly OutstandingOperationHelper _closeOutputOutstandingOperationHelper; - private readonly OutstandingOperationHelper _receiveOutstandingOperationHelper; - private readonly OutstandingOperationHelper _sendOutstandingOperationHelper; - private readonly Stream _innerStream; - private readonly IWebSocketStream _innerStreamAsWebSocketStream; - private readonly string _subProtocol; - - // We are not calling Dispose method on this object in Cleanup method to avoid a race condition while one thread is calling disposing on - // this object and another one is still using WaitAsync. According to Dev11 358715, this should be fine as long as we are not accessing the - // AvailableWaitHandle on this SemaphoreSlim object. - private readonly SemaphoreSlim _sendFrameThrottle; - // locking m_ThisLock protects access to - // - State - // - m_CloseStack - // - m_CloseAsyncStartedReceive - // - m_CloseReceivedTaskCompletionSource - // - m_CloseNetworkConnectionTask - private readonly object _thisLock; - private readonly WebSocketBuffer _internalBuffer; - private readonly KeepAliveTracker _keepAliveTracker; - -#if DEBUG - private volatile string _closeStack; -#endif - - private volatile bool _cleanedUp; - private volatile TaskCompletionSource _closeReceivedTaskCompletionSource; - private volatile Task _closeOutputTask; - private volatile bool _isDisposed; - private volatile Task _closeNetworkConnectionTask; - private volatile bool _closeAsyncStartedReceive; - private volatile WebSocketState _state; - private volatile Task _keepAliveTask; - private volatile WebSocketOperation.ReceiveOperation _receiveOperation; - private volatile WebSocketOperation.SendOperation _sendOperation; - private volatile WebSocketOperation.SendOperation _keepAliveOperation; - private volatile WebSocketOperation.CloseOutputOperation _closeOutputOperation; - private WebSocketCloseStatus? _closeStatus; - private string _closeStatusDescription; - private int _receiveState; - private Exception _pendingException; - - protected WebSocketBase(Stream innerStream, - string subProtocol, - TimeSpan keepAliveInterval, - WebSocketBuffer internalBuffer) - { - Contract.Assert(internalBuffer != null, "'internalBuffer' MUST NOT be NULL."); - WebSocketHelpers.ValidateInnerStream(innerStream); - WebSocketHelpers.ValidateOptions(subProtocol, internalBuffer.ReceiveBufferSize, - internalBuffer.SendBufferSize, keepAliveInterval); - - // s_LoggingEnabled = Logging.On && Logging.WebSockets.Switch.ShouldTrace(TraceEventType.Critical); - string parameters = string.Empty; - /* - if (s_LoggingEnabled) - { - parameters = string.Format(CultureInfo.InvariantCulture, - "ReceiveBufferSize: {0}, SendBufferSize: {1}, Protocols: {2}, KeepAliveInterval: {3}, innerStream: {4}, internalBuffer: {5}", - internalBuffer.ReceiveBufferSize, - internalBuffer.SendBufferSize, - subProtocol, - keepAliveInterval, - Logging.GetObjectLogHash(innerStream), - Logging.GetObjectLogHash(internalBuffer)); - - Logging.Enter(Logging.WebSockets, this, Methods.Initialize, parameters); - } - */ - _thisLock = new object(); - - try - { - _innerStream = innerStream; - _internalBuffer = internalBuffer; - /*if (s_LoggingEnabled) - { - Logging.Associate(Logging.WebSockets, this, m_InnerStream); - Logging.Associate(Logging.WebSockets, this, m_InternalBuffer); - }*/ - - _closeOutstandingOperationHelper = new OutstandingOperationHelper(); - _closeOutputOutstandingOperationHelper = new OutstandingOperationHelper(); - _receiveOutstandingOperationHelper = new OutstandingOperationHelper(); - _sendOutstandingOperationHelper = new OutstandingOperationHelper(); - _state = WebSocketState.Open; - _subProtocol = subProtocol; - _sendFrameThrottle = new SemaphoreSlim(1, 1); - _closeStatus = null; - _closeStatusDescription = null; - _innerStreamAsWebSocketStream = innerStream as IWebSocketStream; - if (_innerStreamAsWebSocketStream != null) - { - _innerStreamAsWebSocketStream.SwitchToOpaqueMode(this); - } - _keepAliveTracker = KeepAliveTracker.Create(keepAliveInterval); - } - finally - { - /*if (s_LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.Initialize, parameters); - }*/ - } - } - /* - internal static bool LoggingEnabled - { - get - { - return s_LoggingEnabled; - } - } - */ - public override WebSocketState State - { - get - { - Contract.Assert(_state != WebSocketState.None, "'m_State' MUST NOT be 'WebSocketState.None'."); - return _state; - } - } - - public override string SubProtocol - { - get - { - return _subProtocol; - } - } - - public override WebSocketCloseStatus? CloseStatus - { - get - { - return _closeStatus; - } - } - - public override string CloseStatusDescription - { - get - { - return _closeStatusDescription; - } - } - - internal WebSocketBuffer InternalBuffer - { - get - { - Contract.Assert(_internalBuffer != null, "'m_InternalBuffer' MUST NOT be NULL."); - return _internalBuffer; - } - } - - protected void StartKeepAliveTimer() - { - _keepAliveTracker.StartTimer(this); - } - - // locking SessionHandle protects access to - // - WSPC (WebSocketProtocolComponent) - // - m_KeepAliveTask - // - m_CloseOutputTask - // - m_LastSendActivity - internal abstract SafeHandle SessionHandle { get; } - - // MultiThreading: ThreadSafe; At most one outstanding call to ReceiveAsync is allowed - public override Task ReceiveAsync(ArraySegment buffer, - CancellationToken cancellationToken) - { - WebSocketHelpers.ValidateArraySegment(buffer, "buffer"); - return ReceiveAsyncCore(buffer, cancellationToken); - } - - private async Task ReceiveAsyncCore(ArraySegment buffer, - CancellationToken cancellationToken) - { - Contract.Assert(buffer.Array != null); - /* - if (s_LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, this, Methods.ReceiveAsync, string.Empty); - } - */ - WebSocketReceiveResult receiveResult; - try - { - ThrowIfPendingException(); - ThrowIfDisposed(); - WebSocketHelpers.ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseSent); - - bool ownsCancellationTokenSource = false; - CancellationToken linkedCancellationToken = CancellationToken.None; - try - { - ownsCancellationTokenSource = _receiveOutstandingOperationHelper.TryStartOperation(cancellationToken, - out linkedCancellationToken); - if (!ownsCancellationTokenSource) - { - lock (_thisLock) - { - if (_closeAsyncStartedReceive) - { - throw new InvalidOperationException( - SR.GetString(SR.net_WebSockets_ReceiveAsyncDisallowedAfterCloseAsync, Methods.CloseAsync, Methods.CloseOutputAsync)); - } - - throw new InvalidOperationException( - SR.GetString(SR.net_Websockets_AlreadyOneOutstandingOperation, Methods.ReceiveAsync)); - } - } - - EnsureReceiveOperation(); - receiveResult = await _receiveOperation.Process(buffer, linkedCancellationToken).SuppressContextFlow(); - /* - if (s_LoggingEnabled && receiveResult.Count > 0) - { - Logging.Dump(Logging.WebSockets, - this, - Methods.ReceiveAsync, - buffer.Array, - buffer.Offset, - receiveResult.Count); - }*/ - } - catch (Exception exception) - { - bool aborted = linkedCancellationToken.IsCancellationRequested; - Abort(); - ThrowIfConvertibleException(Methods.ReceiveAsync, exception, cancellationToken, aborted); - throw; - } - finally - { - _receiveOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); - } - } - finally - {/* - if (s_LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.ReceiveAsync, string.Empty); - }*/ - } - - return receiveResult; - } - - // MultiThreading: ThreadSafe; At most one outstanding call to SendAsync is allowed - public override Task SendAsync(ArraySegment buffer, - WebSocketMessageType messageType, - bool endOfMessage, - CancellationToken cancellationToken) - { - if (messageType != WebSocketMessageType.Binary && - messageType != WebSocketMessageType.Text) - { - throw new ArgumentException(SR.GetString(SR.net_WebSockets_Argument_InvalidMessageType, - messageType, - Methods.SendAsync, - WebSocketMessageType.Binary, - WebSocketMessageType.Text, - Methods.CloseOutputAsync), - "messageType"); - } - - WebSocketHelpers.ValidateArraySegment(buffer, "buffer"); - - return SendAsyncCore(buffer, messageType, endOfMessage, cancellationToken); - } - - private async Task SendAsyncCore(ArraySegment buffer, - WebSocketMessageType messageType, - bool endOfMessage, - CancellationToken cancellationToken) - { - Contract.Assert(messageType == WebSocketMessageType.Binary || messageType == WebSocketMessageType.Text, - "'messageType' MUST be either 'WebSocketMessageType.Binary' or 'WebSocketMessageType.Text'."); - Contract.Assert(buffer.Array != null); - - string inputParameter = string.Empty; - /*if (s_LoggingEnabled) - { - inputParameter = string.Format(CultureInfo.InvariantCulture, - "messageType: {0}, endOfMessage: {1}", - messageType, - endOfMessage); - Logging.Enter(Logging.WebSockets, this, Methods.SendAsync, inputParameter); - }*/ - - try - { - ThrowIfPendingException(); - ThrowIfDisposed(); - WebSocketHelpers.ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived); - bool ownsCancellationTokenSource = false; - CancellationToken linkedCancellationToken = CancellationToken.None; - - try - { - while (!(ownsCancellationTokenSource = _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken))) - { - Task keepAliveTask; - - lock (SessionHandle) - { - keepAliveTask = _keepAliveTask; - - if (keepAliveTask == null) - { - // Check whether there is still another outstanding send operation - // Potentially the keepAlive operation has completed before this thread - // was able to enter the SessionHandle-lock. - _sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); - if (ownsCancellationTokenSource = _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken)) - { - break; - } - else - { - throw new InvalidOperationException( - SR.GetString(SR.net_Websockets_AlreadyOneOutstandingOperation, Methods.SendAsync)); - } - } - } - - await keepAliveTask.SuppressContextFlow(); - ThrowIfPendingException(); - - _sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); - } - /* - if (s_LoggingEnabled && buffer.Count > 0) - { - Logging.Dump(Logging.WebSockets, - this, - Methods.SendAsync, - buffer.Array, - buffer.Offset, - buffer.Count); - }*/ - - int position = buffer.Offset; - - EnsureSendOperation(); - _sendOperation.BufferType = GetBufferType(messageType, endOfMessage); - await _sendOperation.Process(buffer, linkedCancellationToken).SuppressContextFlow(); - } - catch (Exception exception) - { - bool aborted = linkedCancellationToken.IsCancellationRequested; - Abort(); - ThrowIfConvertibleException(Methods.SendAsync, exception, cancellationToken, aborted); - throw; - } - finally - { - _sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); - } - } - finally - { - /*if (s_LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.SendAsync, inputParameter); - }*/ - } - } - - private async Task SendFrameAsync(IList> sendBuffers, CancellationToken cancellationToken) - { - bool sendFrameLockTaken = false; - try - { - await _sendFrameThrottle.WaitAsync(cancellationToken).SuppressContextFlow(); - sendFrameLockTaken = true; - - if (sendBuffers.Count > 1 && - _innerStreamAsWebSocketStream != null && - _innerStreamAsWebSocketStream.SupportsMultipleWrite) - { - await _innerStreamAsWebSocketStream.MultipleWriteAsync(sendBuffers, - cancellationToken).SuppressContextFlow(); - } - else - { - foreach (ArraySegment buffer in sendBuffers) - { - await _innerStream.WriteAsync(buffer.Array, - buffer.Offset, - buffer.Count, - cancellationToken).SuppressContextFlow(); - } - } - } - catch (ObjectDisposedException objectDisposedException) - { - throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, objectDisposedException); - } - catch (NotSupportedException notSupportedException) - { - throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, notSupportedException); - } - finally - { - if (sendFrameLockTaken) - { - _sendFrameThrottle.Release(); - } - } - } - - // MultiThreading: ThreadSafe; No-op if already in a terminal state - public override void Abort() - { - /*if (s_LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, this, Methods.Abort, string.Empty); - }*/ - - bool thisLockTaken = false; - bool sessionHandleLockTaken = false; - try - { - if (WebSocketHelpers.IsStateTerminal(State)) - { - return; - } - - TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - if (WebSocketHelpers.IsStateTerminal(State)) - { - return; - } - - _state = WebSocketState.Aborted; - -#if DEBUG && NET451 - string stackTrace = new StackTrace().ToString(); - if (_closeStack == null) - { - _closeStack = stackTrace; - } - /* - if (s_LoggingEnabled) - { - string message = string.Format(CultureInfo.InvariantCulture, "Stack: {0}", stackTrace); - Logging.PrintWarning(Logging.WebSockets, this, Methods.Abort, message); - }*/ -#endif - - // Abort any outstanding IO operations. - if (SessionHandle != null && !SessionHandle.IsClosed && !SessionHandle.IsInvalid) - { - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketAbortHandle(SessionHandle); - } - - _receiveOutstandingOperationHelper.CancelIO(); - _sendOutstandingOperationHelper.CancelIO(); - _closeOutputOutstandingOperationHelper.CancelIO(); - _closeOutstandingOperationHelper.CancelIO(); - if (_innerStreamAsWebSocketStream != null) - { - _innerStreamAsWebSocketStream.Abort(); - } - CleanUp(); - } - finally - { - ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); - /*if (s_LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.Abort, string.Empty); - }*/ - } - } - - // MultiThreading: ThreadSafe; No-op if already in a terminal state - public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, - string statusDescription, - CancellationToken cancellationToken) - { - WebSocketHelpers.ValidateCloseStatus(closeStatus, statusDescription); - - return CloseOutputAsyncCore(closeStatus, statusDescription, cancellationToken); - } - - private async Task CloseOutputAsyncCore(WebSocketCloseStatus closeStatus, - string statusDescription, - CancellationToken cancellationToken) - { - string inputParameter = string.Empty; - /*if (s_LoggingEnabled) - { - inputParameter = string.Format(CultureInfo.InvariantCulture, - "closeStatus: {0}, statusDescription: {1}", - closeStatus, - statusDescription); - Logging.Enter(Logging.WebSockets, this, Methods.CloseOutputAsync, inputParameter); - }*/ - - try - { - ThrowIfPendingException(); - if (WebSocketHelpers.IsStateTerminal(State)) - { - return; - } - ThrowIfDisposed(); - - bool thisLockTaken = false; - bool sessionHandleLockTaken = false; - bool needToCompleteSendOperation = false; - bool ownsCloseOutputCancellationTokenSource = false; - bool ownsSendCancellationTokenSource = false; - CancellationToken linkedCancellationToken = CancellationToken.None; - try - { - TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - ThrowIfPendingException(); - ThrowIfDisposed(); - - if (WebSocketHelpers.IsStateTerminal(State)) - { - return; - } - - WebSocketHelpers.ThrowOnInvalidState(State, WebSocketState.Open, WebSocketState.CloseReceived); - ownsCloseOutputCancellationTokenSource = _closeOutputOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); - if (!ownsCloseOutputCancellationTokenSource) - { - Task closeOutputTask = _closeOutputTask; - - if (closeOutputTask != null) - { - ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); - await closeOutputTask.SuppressContextFlow(); - TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - } - } - else - { - needToCompleteSendOperation = true; - while (!(ownsSendCancellationTokenSource = - _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, - out linkedCancellationToken))) - { - if (_keepAliveTask != null) - { - Task keepAliveTask = _keepAliveTask; - - ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); - await keepAliveTask.SuppressContextFlow(); - TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - - ThrowIfPendingException(); - } - else - { - throw new InvalidOperationException( - SR.GetString(SR.net_Websockets_AlreadyOneOutstandingOperation, Methods.SendAsync)); - } - - _sendOutstandingOperationHelper.CompleteOperation(ownsSendCancellationTokenSource); - } - - EnsureCloseOutputOperation(); - _closeOutputOperation.CloseStatus = closeStatus; - _closeOutputOperation.CloseReason = statusDescription; - _closeOutputTask = _closeOutputOperation.Process(null, linkedCancellationToken); - - ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); - await _closeOutputTask.SuppressContextFlow(); - TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - - if (OnCloseOutputCompleted()) - { - bool callCompleteOnCloseCompleted = false; - - try - { - callCompleteOnCloseCompleted = await StartOnCloseCompleted( - thisLockTaken, sessionHandleLockTaken, linkedCancellationToken).SuppressContextFlow(); - } - catch (Exception) - { - // If an exception is thrown we know that the locks have been released, - // because we enforce IWebSocketStream.CloseNetworkConnectionAsync to yield - ResetFlagsAndTakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - throw; - } - - if (callCompleteOnCloseCompleted) - { - ResetFlagsAndTakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - FinishOnCloseCompleted(); - } - } - } - } - catch (Exception exception) - { - bool aborted = linkedCancellationToken.IsCancellationRequested; - Abort(); - ThrowIfConvertibleException(Methods.CloseOutputAsync, exception, cancellationToken, aborted); - throw; - } - finally - { - _closeOutputOutstandingOperationHelper.CompleteOperation(ownsCloseOutputCancellationTokenSource); - - if (needToCompleteSendOperation) - { - _sendOutstandingOperationHelper.CompleteOperation(ownsSendCancellationTokenSource); - } - - _closeOutputTask = null; - ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); - } - } - finally - { - /*if (s_LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.CloseOutputAsync, inputParameter); - }*/ - } - } - - // returns TRUE if the caller should also call StartOnCloseCompleted - private bool OnCloseOutputCompleted() - { - if (WebSocketHelpers.IsStateTerminal(State)) - { - return false; - } - - switch (State) - { - case WebSocketState.Open: - _state = WebSocketState.CloseSent; - return false; - case WebSocketState.CloseReceived: - return true; - default: - return false; - } - } - - // MultiThreading: This method has to be called under a m_ThisLock-lock - // ReturnValue: This method returns true only if CompleteOnCloseCompleted needs to be called - // If this method returns true all locks were released before starting the IO operation - // and they have to be retaken by the caller before calling CompleteOnCloseCompleted - // Exception handling: If an exception is thrown from await StartOnCloseCompleted - // it always means the locks have been released already - so the caller has to retake the - // locks in the catch-block. - // This is ensured by enforcing a Task.Yield for IWebSocketStream.CloseNetowrkConnectionAsync - private async Task StartOnCloseCompleted(bool thisLockTakenSnapshot, - bool sessionHandleLockTakenSnapshot, - CancellationToken cancellationToken) - { - Contract.Assert(thisLockTakenSnapshot, "'thisLockTakenSnapshot' MUST be 'true' at this point."); - - if (WebSocketHelpers.IsStateTerminal(_state)) - { - return false; - } - - _state = WebSocketState.Closed; - -#if DEBUG && NET451 - if (_closeStack == null) - { - _closeStack = new StackTrace().ToString(); - } -#endif - - if (_innerStreamAsWebSocketStream != null) - { - bool thisLockTaken = thisLockTakenSnapshot; - bool sessionHandleLockTaken = sessionHandleLockTakenSnapshot; - - try - { - if (_closeNetworkConnectionTask == null) - { - _closeNetworkConnectionTask = - _innerStreamAsWebSocketStream.CloseNetworkConnectionAsync(cancellationToken); - } - - if (thisLockTaken && sessionHandleLockTaken) - { - ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); - } - else if (thisLockTaken) - { - ReleaseLock(_thisLock, ref thisLockTaken); - } - - await _closeNetworkConnectionTask.SuppressContextFlow(); - } - catch (Exception closeNetworkConnectionTaskException) - { - if (!CanHandleExceptionDuringClose(closeNetworkConnectionTaskException)) - { - ThrowIfConvertibleException(Methods.StartOnCloseCompleted, - closeNetworkConnectionTaskException, - cancellationToken, - cancellationToken.IsCancellationRequested); - throw; - } - } - } - - return true; - } - - // MultiThreading: This method has to be called under a thisLock-lock - private void FinishOnCloseCompleted() - { - CleanUp(); - } - - // MultiThreading: ThreadSafe; No-op if already in a terminal state - public override Task CloseAsync(WebSocketCloseStatus closeStatus, - string statusDescription, - CancellationToken cancellationToken) - { - WebSocketHelpers.ValidateCloseStatus(closeStatus, statusDescription); - return CloseAsyncCore(closeStatus, statusDescription, cancellationToken); - } - - private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, - string statusDescription, - CancellationToken cancellationToken) - { - string inputParameter = string.Empty; - /*if (s_LoggingEnabled) - { - inputParameter = string.Format(CultureInfo.InvariantCulture, - "closeStatus: {0}, statusDescription: {1}", - closeStatus, - statusDescription); - Logging.Enter(Logging.WebSockets, this, Methods.CloseAsync, inputParameter); - }*/ - - try - { - ThrowIfPendingException(); - if (WebSocketHelpers.IsStateTerminal(State)) - { - return; - } - ThrowIfDisposed(); - - bool lockTaken = false; - Monitor.Enter(_thisLock, ref lockTaken); - bool ownsCloseCancellationTokenSource = false; - CancellationToken linkedCancellationToken = CancellationToken.None; - try - { - ThrowIfPendingException(); - if (WebSocketHelpers.IsStateTerminal(State)) - { - return; - } - ThrowIfDisposed(); - WebSocketHelpers.ThrowOnInvalidState(State, - WebSocketState.Open, WebSocketState.CloseReceived, WebSocketState.CloseSent); - - Task closeOutputTask; - ownsCloseCancellationTokenSource = _closeOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); - if (ownsCloseCancellationTokenSource) - { - closeOutputTask = _closeOutputTask; - if (closeOutputTask == null && State != WebSocketState.CloseSent) - { - if (_closeReceivedTaskCompletionSource == null) - { - _closeReceivedTaskCompletionSource = new TaskCompletionSource(); - } - - closeOutputTask = CloseOutputAsync(closeStatus, - statusDescription, - linkedCancellationToken); - } - } - else - { - Contract.Assert(_closeReceivedTaskCompletionSource != null, - "'m_CloseReceivedTaskCompletionSource' MUST NOT be NULL."); - closeOutputTask = _closeReceivedTaskCompletionSource.Task; - } - - if (closeOutputTask != null) - { - ReleaseLock(_thisLock, ref lockTaken); - try - { - await closeOutputTask.SuppressContextFlow(); - } - catch (Exception closeOutputError) - { - Monitor.Enter(_thisLock, ref lockTaken); - - if (!CanHandleExceptionDuringClose(closeOutputError)) - { - ThrowIfConvertibleException(Methods.CloseOutputAsync, - closeOutputError, - cancellationToken, - linkedCancellationToken.IsCancellationRequested); - throw; - } - } - - // When closeOutputTask != null and an exception thrown from await closeOutputTask is handled, - // the lock will be taken in the catch-block. So the logic here avoids taking the lock twice. - if (!lockTaken) - { - Monitor.Enter(_thisLock, ref lockTaken); - } - } - - if (OnCloseOutputCompleted()) - { - bool callCompleteOnCloseCompleted = false; - - try - { - // linkedCancellationToken can be CancellationToken.None if ownsCloseCancellationTokenSource==false - // This is still ok because OnCloseOutputCompleted won't start any IO operation in this case - callCompleteOnCloseCompleted = await StartOnCloseCompleted( - lockTaken, false, linkedCancellationToken).SuppressContextFlow(); - } - catch (Exception) - { - // If an exception is thrown we know that the locks have been released, - // because we enforce IWebSocketStream.CloseNetworkConnectionAsync to yield - ResetFlagAndTakeLock(_thisLock, ref lockTaken); - throw; - } - - if (callCompleteOnCloseCompleted) - { - ResetFlagAndTakeLock(_thisLock, ref lockTaken); - FinishOnCloseCompleted(); - } - } - - if (WebSocketHelpers.IsStateTerminal(State)) - { - return; - } - - linkedCancellationToken = CancellationToken.None; - - bool ownsReceiveCancellationTokenSource = _receiveOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); - if (ownsReceiveCancellationTokenSource) - { - _closeAsyncStartedReceive = true; - ArraySegment closeMessageBuffer = - new ArraySegment(new byte[WebSocketBuffer.MinReceiveBufferSize]); - EnsureReceiveOperation(); - Task receiveAsyncTask = _receiveOperation.Process(closeMessageBuffer, - linkedCancellationToken); - ReleaseLock(_thisLock, ref lockTaken); - - WebSocketReceiveResult receiveResult = null; - try - { - receiveResult = await receiveAsyncTask.SuppressContextFlow(); - } - catch (Exception receiveException) - { - Monitor.Enter(_thisLock, ref lockTaken); - - if (!CanHandleExceptionDuringClose(receiveException)) - { - ThrowIfConvertibleException(Methods.CloseAsync, - receiveException, - cancellationToken, - linkedCancellationToken.IsCancellationRequested); - throw; - } - } - - // receiveResult is NEVER NULL if WebSocketBase.ReceiveOperation.Process completes successfully - // - but in the close code path we handle some exception if another thread was able to tranistion - // the state into Closed successfully. In this case receiveResult can be NULL and it is safe to - // skip the statements in the if-block. - if (receiveResult != null) - { - /*if (s_LoggingEnabled && receiveResult.Count > 0) - { - Logging.Dump(Logging.WebSockets, - this, - Methods.ReceiveAsync, - closeMessageBuffer.Array, - closeMessageBuffer.Offset, - receiveResult.Count); - }*/ - - if (receiveResult.MessageType != WebSocketMessageType.Close) - { - throw new WebSocketException(WebSocketError.InvalidMessageType, - SR.GetString(SR.net_WebSockets_InvalidMessageType, - typeof(WebSocket).Name + "." + Methods.CloseAsync, - typeof(WebSocket).Name + "." + Methods.CloseOutputAsync, - receiveResult.MessageType)); - } - } - } - else - { - _receiveOutstandingOperationHelper.CompleteOperation(ownsReceiveCancellationTokenSource); - ReleaseLock(_thisLock, ref lockTaken); - await _closeReceivedTaskCompletionSource.Task.SuppressContextFlow(); - } - - // When ownsReceiveCancellationTokenSource is true and an exception is thrown, the lock will be taken. - // So this logic here is to avoid taking the lock twice. - if (!lockTaken) - { - Monitor.Enter(_thisLock, ref lockTaken); - } - - if (!WebSocketHelpers.IsStateTerminal(State)) - { - bool ownsSendCancellationSource = false; - try - { - // We know that the CloseFrame has been sent at this point. So no Send-operation is allowed anymore and we - // can hijack the m_SendOutstandingOperationHelper to create a linkedCancellationToken - ownsSendCancellationSource = _sendOutstandingOperationHelper.TryStartOperation(cancellationToken, out linkedCancellationToken); - Contract.Assert(ownsSendCancellationSource, "'ownsSendCancellationSource' MUST be 'true' at this point."); - - bool callCompleteOnCloseCompleted = false; - - try - { - // linkedCancellationToken can be CancellationToken.None if ownsCloseCancellationTokenSource==false - // This is still ok because OnCloseOutputCompleted won't start any IO operation in this case - callCompleteOnCloseCompleted = await StartOnCloseCompleted( - lockTaken, false, linkedCancellationToken).SuppressContextFlow(); - } - catch (Exception) - { - // If an exception is thrown we know that the locks have been released, - // because we enforce IWebSocketStream.CloseNetworkConnectionAsync to yield - ResetFlagAndTakeLock(_thisLock, ref lockTaken); - throw; - } - - if (callCompleteOnCloseCompleted) - { - ResetFlagAndTakeLock(_thisLock, ref lockTaken); - FinishOnCloseCompleted(); - } - } - finally - { - _sendOutstandingOperationHelper.CompleteOperation(ownsSendCancellationSource); - } - } - } - catch (Exception exception) - { - bool aborted = linkedCancellationToken.IsCancellationRequested; - Abort(); - ThrowIfConvertibleException(Methods.CloseAsync, exception, cancellationToken, aborted); - throw; - } - finally - { - _closeOutstandingOperationHelper.CompleteOperation(ownsCloseCancellationTokenSource); - ReleaseLock(_thisLock, ref lockTaken); - } - } - finally - { - /*if (s_LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, this, Methods.CloseAsync, inputParameter); - }*/ - } - } - - // MultiThreading: ThreadSafe; No-op if already in a terminal state - [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_sendFrameThrottle", - Justification = "SemaphoreSlim.Dispose is not threadsafe and can cause NullRef exceptions on other threads." + - "Also according to the CLR Dev11#358715) there is no need to dispose SemaphoreSlim if the ManualResetEvent " + - "is not used.")] - public override void Dispose() - { - if (_isDisposed) - { - return; - } - - bool thisLockTaken = false; - bool sessionHandleLockTaken = false; - - try - { - TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - - if (_isDisposed) - { - return; - } - - if (!WebSocketHelpers.IsStateTerminal(State)) - { - Abort(); - } - else - { - CleanUp(); - } - - _isDisposed = true; - } - finally - { - ReleaseLocks(ref thisLockTaken, ref sessionHandleLockTaken); - } - } - - private void ResetFlagAndTakeLock(object lockObject, ref bool thisLockTaken) - { - Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); - thisLockTaken = false; - Monitor.Enter(lockObject, ref thisLockTaken); - } - - private void ResetFlagsAndTakeLocks(ref bool thisLockTaken, ref bool sessionHandleLockTaken) - { - thisLockTaken = false; - sessionHandleLockTaken = false; - TakeLocks(ref thisLockTaken, ref sessionHandleLockTaken); - } - - private void TakeLocks(ref bool thisLockTaken, ref bool sessionHandleLockTaken) - { - Contract.Assert(_thisLock != null, "'m_ThisLock' MUST NOT be NULL."); - Contract.Assert(SessionHandle != null, "'SessionHandle' MUST NOT be NULL."); - - Monitor.Enter(SessionHandle, ref sessionHandleLockTaken); - Monitor.Enter(_thisLock, ref thisLockTaken); - } - - private void ReleaseLocks(ref bool thisLockTaken, ref bool sessionHandleLockTaken) - { - Contract.Assert(_thisLock != null, "'m_ThisLock' MUST NOT be NULL."); - Contract.Assert(SessionHandle != null, "'SessionHandle' MUST NOT be NULL."); - - if (thisLockTaken || sessionHandleLockTaken) - { -#if !NETSTANDARD1_3 - RuntimeHelpers.PrepareConstrainedRegions(); -#endif - try - { - } - finally - { - if (thisLockTaken) - { - Monitor.Exit(_thisLock); - thisLockTaken = false; - } - - if (sessionHandleLockTaken) - { - Monitor.Exit(SessionHandle); - sessionHandleLockTaken = false; - } - } - } - } - - private void EnsureReceiveOperation() - { - if (_receiveOperation == null) - { - lock (_thisLock) - { - if (_receiveOperation == null) - { - _receiveOperation = new WebSocketOperation.ReceiveOperation(this); - } - } - } - } - - private void EnsureSendOperation() - { - if (_sendOperation == null) - { - lock (_thisLock) - { - if (_sendOperation == null) - { - _sendOperation = new WebSocketOperation.SendOperation(this); - } - } - } - } - - private void EnsureKeepAliveOperation() - { - if (_keepAliveOperation == null) - { - lock (_thisLock) - { - if (_keepAliveOperation == null) - { - WebSocketOperation.SendOperation keepAliveOperation = new WebSocketOperation.SendOperation(this); - keepAliveOperation.BufferType = UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UnsolicitedPong; - _keepAliveOperation = keepAliveOperation; - } - } - } - } - - private void EnsureCloseOutputOperation() - { - if (_closeOutputOperation == null) - { - lock (_thisLock) - { - if (_closeOutputOperation == null) - { - _closeOutputOperation = new WebSocketOperation.CloseOutputOperation(this); - } - } - } - } - - private static void ReleaseLock(object lockObject, ref bool lockTaken) - { - Contract.Assert(lockObject != null, "'lockObject' MUST NOT be NULL."); - if (lockTaken) - { -#if !NETSTANDARD1_3 - RuntimeHelpers.PrepareConstrainedRegions(); -#endif - try - { - } - finally - { - Monitor.Exit(lockObject); - lockTaken = false; - } - } - } - - private static UnsafeNativeMethods.WebSocketProtocolComponent.BufferType GetBufferType(WebSocketMessageType messageType, - bool endOfMessage) - { - Contract.Assert(messageType == WebSocketMessageType.Binary || messageType == WebSocketMessageType.Text, - string.Format(CultureInfo.InvariantCulture, - "The value of 'messageType' ({0}) is invalid. Valid message types: '{1}, {2}'", - messageType, - WebSocketMessageType.Binary, - WebSocketMessageType.Text)); - - if (messageType == WebSocketMessageType.Text) - { - if (endOfMessage) - { - return UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message; - } - - return UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment; - } - else - { - if (endOfMessage) - { - return UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage; - } - - return UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment; - } - } - - private static WebSocketMessageType GetMessageType(UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType) - { - switch (bufferType) - { - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close: - return WebSocketMessageType.Close; - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment: - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage: - return WebSocketMessageType.Binary; - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment: - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message: - return WebSocketMessageType.Text; - default: - // This indicates a contract violation of the websocket protocol component, - // because we currently don't support any WebSocket extensions and would - // not accept a Websocket handshake requesting extensions - Contract.Assert(false, - string.Format(CultureInfo.InvariantCulture, - "The value of 'bufferType' ({0}) is invalid. Valid buffer types: {1}, {2}, {3}, {4}, {5}.", - bufferType, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message)); - - throw new WebSocketException(WebSocketError.NativeError, - SR.GetString(SR.net_WebSockets_InvalidBufferType, - bufferType, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message)); - } - } - - internal void ValidateNativeBuffers(UnsafeNativeMethods.WebSocketProtocolComponent.Action action, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers, - uint dataBufferCount) - { - _internalBuffer.ValidateNativeBuffers(action, bufferType, dataBuffers, dataBufferCount); - } - - internal void ThrowIfClosedOrAborted() - { - if (State == WebSocketState.Closed || State == WebSocketState.Aborted) - { - throw new WebSocketException(WebSocketError.InvalidState, - SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, GetType().FullName, State)); - } - } - - private void ThrowIfAborted(bool aborted, Exception innerException) - { - if (aborted) - { - throw new WebSocketException(WebSocketError.InvalidState, - SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, GetType().FullName, WebSocketState.Aborted), - innerException); - } - } - - private bool CanHandleExceptionDuringClose(Exception error) - { - Contract.Assert(error != null, "'error' MUST NOT be NULL."); - - if (State != WebSocketState.Closed) - { - return false; - } - - return error is OperationCanceledException || - error is WebSocketException || - // error is SocketException || - // error is HttpListenerException || - error is IOException; - } - - // We only want to throw an OperationCanceledException if the CancellationToken passed - // down from the caller is canceled - not when Abort is called on another thread and - // the linkedCancellationToken is canceled. - private void ThrowIfConvertibleException(string methodName, - Exception exception, - CancellationToken cancellationToken, - bool aborted) - { - Contract.Assert(exception != null, "'exception' MUST NOT be NULL."); - /* - if (s_LoggingEnabled && !string.IsNullOrEmpty(methodName)) - { - Logging.Exception(Logging.WebSockets, this, methodName, exception); - }*/ - - OperationCanceledException operationCanceledException = exception as OperationCanceledException; - if (operationCanceledException != null) - { - if (cancellationToken.IsCancellationRequested || - !aborted) - { - return; - } - ThrowIfAborted(aborted, exception); - } - - WebSocketException convertedException = exception as WebSocketException; - if (convertedException != null) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfAborted(aborted, convertedException); - return; - } - /* - SocketException socketException = exception as SocketException; - if (socketException != null) - { - convertedException = new WebSocketException(socketException.NativeErrorCode, socketException); - } - HttpListenerException httpListenerException = exception as HttpListenerException; - if (httpListenerException != null) - { - convertedException = new WebSocketException(httpListenerException.ErrorCode, httpListenerException); - } - - IOException ioException = exception as IOException; - if (ioException != null) - { - socketException = exception.InnerException as SocketException; - if (socketException != null) - { - convertedException = new WebSocketException(socketException.NativeErrorCode, ioException); - } - } -*/ - if (convertedException != null) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfAborted(aborted, convertedException); - throw convertedException; - } - - AggregateException aggregateException = exception as AggregateException; - if (aggregateException != null) - { - // Collapse possibly nested graph into a flat list. - // Empty inner exception list is unlikely but possible via public api. - ReadOnlyCollection unwrappedExceptions = aggregateException.Flatten().InnerExceptions; - if (unwrappedExceptions.Count == 0) - { - return; - } - - foreach (Exception unwrappedException in unwrappedExceptions) - { - ThrowIfConvertibleException(null, unwrappedException, cancellationToken, aborted); - } - } - } - - private void CleanUp() - { - // Multithreading: This method is always called under the m_ThisLock lock - if (_cleanedUp) - { - return; - } - - _cleanedUp = true; - - if (SessionHandle != null) - { - SessionHandle.Dispose(); - } - - if (_internalBuffer != null) - { - _internalBuffer.Dispose(this.State); - } - - if (_receiveOutstandingOperationHelper != null) - { - _receiveOutstandingOperationHelper.Dispose(); - } - - if (_sendOutstandingOperationHelper != null) - { - _sendOutstandingOperationHelper.Dispose(); - } - - if (_closeOutputOutstandingOperationHelper != null) - { - _closeOutputOutstandingOperationHelper.Dispose(); - } - - if (_closeOutstandingOperationHelper != null) - { - _closeOutstandingOperationHelper.Dispose(); - } - - if (_innerStream != null) - { - try - { - _innerStream.Dispose(); - } - catch (ObjectDisposedException) - { - } - catch (IOException) - { - } - /*catch (SocketException) - { - }*/ - catch (Exception) - { - } - } - - _keepAliveTracker.Dispose(); - } - - private void OnBackgroundTaskException(Exception exception) - { - if (Interlocked.CompareExchange(ref _pendingException, exception, null) == null) - { - /*if (s_LoggingEnabled) - { - Logging.Exception(Logging.WebSockets, this, Methods.Fault, exception); - }*/ - Abort(); - } - } - - private void ThrowIfPendingException() - { - Exception pendingException = Interlocked.Exchange(ref _pendingException, null); - if (pendingException != null) - { - throw new WebSocketException(WebSocketError.Faulted, pendingException); - } - } - - private void ThrowIfDisposed() - { - if (_isDisposed) - { - throw new ObjectDisposedException(GetType().FullName); - } - } - - private void UpdateReceiveState(int newReceiveState, int expectedReceiveState) - { - int receiveState; - if ((receiveState = Interlocked.Exchange(ref _receiveState, newReceiveState)) != expectedReceiveState) - { - Contract.Assert(false, - string.Format(CultureInfo.InvariantCulture, - "'m_ReceiveState' had an invalid value '{0}'. The expected value was '{1}'.", - receiveState, - expectedReceiveState)); - } - } - - private bool StartOnCloseReceived(ref bool thisLockTaken) - { - ThrowIfDisposed(); - - if (WebSocketHelpers.IsStateTerminal(State) || State == WebSocketState.CloseReceived) - { - return false; - } - - Monitor.Enter(_thisLock, ref thisLockTaken); - if (WebSocketHelpers.IsStateTerminal(State) || State == WebSocketState.CloseReceived) - { - return false; - } - - if (State == WebSocketState.Open) - { - _state = WebSocketState.CloseReceived; - - if (_closeReceivedTaskCompletionSource == null) - { - _closeReceivedTaskCompletionSource = new TaskCompletionSource(); - } - - return false; - } - - return true; - } - - private void FinishOnCloseReceived(WebSocketCloseStatus closeStatus, - string closeStatusDescription) - { - if (_closeReceivedTaskCompletionSource != null) - { - _closeReceivedTaskCompletionSource.TrySetResult(null); - } - - _closeStatus = closeStatus; - _closeStatusDescription = closeStatusDescription; - /* - if (s_LoggingEnabled) - { - string parameters = string.Format(CultureInfo.InvariantCulture, - "closeStatus: {0}, closeStatusDescription: {1}, m_State: {2}", - closeStatus, closeStatusDescription, m_State); - - Logging.PrintInfo(Logging.WebSockets, this, Methods.FinishOnCloseReceived, parameters); - }*/ - } - - private async static void OnKeepAlive(object sender) - { - Contract.Assert(sender != null, "'sender' MUST NOT be NULL."); - Contract.Assert((sender as WebSocketBase) != null, "'sender as WebSocketBase' MUST NOT be NULL."); - - WebSocketBase thisPtr = sender as WebSocketBase; - bool lockTaken = false; - /* - if (s_LoggingEnabled) - { - Logging.Enter(Logging.WebSockets, thisPtr, Methods.OnKeepAlive, string.Empty); - }*/ - - CancellationToken linkedCancellationToken = CancellationToken.None; - try - { - Monitor.Enter(thisPtr.SessionHandle, ref lockTaken); - - if (thisPtr._isDisposed || - thisPtr._state != WebSocketState.Open || - thisPtr._closeOutputTask != null) - { - return; - } - - if (thisPtr._keepAliveTracker.ShouldSendKeepAlive()) - { - bool ownsCancellationTokenSource = false; - try - { - ownsCancellationTokenSource = thisPtr._sendOutstandingOperationHelper.TryStartOperation(CancellationToken.None, out linkedCancellationToken); - if (ownsCancellationTokenSource) - { - thisPtr.EnsureKeepAliveOperation(); - thisPtr._keepAliveTask = thisPtr._keepAliveOperation.Process(null, linkedCancellationToken); - ReleaseLock(thisPtr.SessionHandle, ref lockTaken); - await thisPtr._keepAliveTask.SuppressContextFlow(); - } - } - finally - { - if (!lockTaken) - { - Monitor.Enter(thisPtr.SessionHandle, ref lockTaken); - } - thisPtr._sendOutstandingOperationHelper.CompleteOperation(ownsCancellationTokenSource); - thisPtr._keepAliveTask = null; - } - - thisPtr._keepAliveTracker.ResetTimer(); - } - } - catch (Exception exception) - { - try - { - thisPtr.ThrowIfConvertibleException(Methods.OnKeepAlive, - exception, - CancellationToken.None, - linkedCancellationToken.IsCancellationRequested); - throw; - } - catch (Exception backgroundException) - { - thisPtr.OnBackgroundTaskException(backgroundException); - } - } - finally - { - ReleaseLock(thisPtr.SessionHandle, ref lockTaken); - /* - if (s_LoggingEnabled) - { - Logging.Exit(Logging.WebSockets, thisPtr, Methods.OnKeepAlive, string.Empty); - }*/ - } - } - - private abstract class WebSocketOperation - { - private readonly WebSocketBase _webSocket; - - internal WebSocketOperation(WebSocketBase webSocket) - { - Contract.Assert(webSocket != null, "'webSocket' MUST NOT be NULL."); - _webSocket = webSocket; - } - - public WebSocketReceiveResult ReceiveResult { get; protected set; } - protected abstract int BufferCount { get; } - protected abstract UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue ActionQueue { get; } - protected abstract void Initialize(ArraySegment? buffer, CancellationToken cancellationToken); - protected abstract bool ShouldContinue(CancellationToken cancellationToken); - - // Multi-Threading: This method has to be called under a SessionHandle-lock. It returns true if a - // close frame was received. Handling the received close frame might involve IO - to make the locking - // strategy easier and reduce one level in the await-hierarchy the IO is kicked off by the caller. - protected abstract bool ProcessAction_NoAction(); - - protected virtual void ProcessAction_IndicateReceiveComplete( - ArraySegment? buffer, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, - UnsafeNativeMethods.WebSocketProtocolComponent.Action action, - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers, - uint dataBufferCount, - IntPtr actionContext) - { - throw new NotImplementedException(); - } - - protected abstract void Cleanup(); - - internal async Task Process(ArraySegment? buffer, - CancellationToken cancellationToken) - { - Contract.Assert(BufferCount >= 1 && BufferCount <= 2, "'bufferCount' MUST ONLY BE '1' or '2'."); - - bool sessionHandleLockTaken = false; - ReceiveResult = null; - try - { - Monitor.Enter(_webSocket.SessionHandle, ref sessionHandleLockTaken); - _webSocket.ThrowIfPendingException(); - Initialize(buffer, cancellationToken); - - while (ShouldContinue(cancellationToken)) - { - UnsafeNativeMethods.WebSocketProtocolComponent.Action action; - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType; - - bool completed = false; - while (!completed) - { - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers = - new UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[BufferCount]; - uint dataBufferCount = (uint)BufferCount; - IntPtr actionContext; - - _webSocket.ThrowIfDisposed(); - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketGetAction(_webSocket, - ActionQueue, - dataBuffers, - ref dataBufferCount, - out action, - out bufferType, - out actionContext); - - switch (action) - { - case UnsafeNativeMethods.WebSocketProtocolComponent.Action.NoAction: - if (ProcessAction_NoAction()) - { - // A close frame was received - - Contract.Assert(ReceiveResult.Count == 0, "'receiveResult.Count' MUST be 0."); - Contract.Assert(ReceiveResult.CloseStatus != null, "'receiveResult.CloseStatus' MUST NOT be NULL for message type 'Close'."); - bool thisLockTaken = false; - try - { - if (_webSocket.StartOnCloseReceived(ref thisLockTaken)) - { - // If StartOnCloseReceived returns true the WebSocket close handshake has been completed - // so there is no need to retake the SessionHandle-lock. - // m_ThisLock lock is guaranteed to be taken by StartOnCloseReceived when returning true - ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); - bool callCompleteOnCloseCompleted = false; - - try - { - callCompleteOnCloseCompleted = await _webSocket.StartOnCloseCompleted( - thisLockTaken, sessionHandleLockTaken, cancellationToken).SuppressContextFlow(); - } - catch (Exception) - { - // If an exception is thrown we know that the locks have been released, - // because we enforce IWebSocketStream.CloseNetworkConnectionAsync to yield - _webSocket.ResetFlagAndTakeLock(_webSocket._thisLock, ref thisLockTaken); - throw; - } - - if (callCompleteOnCloseCompleted) - { - _webSocket.ResetFlagAndTakeLock(_webSocket._thisLock, ref thisLockTaken); - _webSocket.FinishOnCloseCompleted(); - } - } - _webSocket.FinishOnCloseReceived(ReceiveResult.CloseStatus.Value, ReceiveResult.CloseStatusDescription); - } - finally - { - if (thisLockTaken) - { - ReleaseLock(_webSocket._thisLock, ref thisLockTaken); - } - } - } - completed = true; - break; - case UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateReceiveComplete: - ProcessAction_IndicateReceiveComplete(buffer, - bufferType, - action, - dataBuffers, - dataBufferCount, - actionContext); - break; - case UnsafeNativeMethods.WebSocketProtocolComponent.Action.ReceiveFromNetwork: - int count = 0; - try - { - ArraySegment payload = _webSocket._internalBuffer.ConvertNativeBuffer(action, dataBuffers[0], bufferType); - - ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); - WebSocketHelpers.ThrowIfConnectionAborted(_webSocket._innerStream, true); - try - { - Task readTask = _webSocket._innerStream.ReadAsync(payload.Array, - payload.Offset, - payload.Count, - cancellationToken); - count = await readTask.SuppressContextFlow(); - _webSocket._keepAliveTracker.OnDataReceived(); - } - catch (ObjectDisposedException objectDisposedException) - { - throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, objectDisposedException); - } - catch (NotSupportedException notSupportedException) - { - throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, notSupportedException); - } - Monitor.Enter(_webSocket.SessionHandle, ref sessionHandleLockTaken); - _webSocket.ThrowIfPendingException(); - // If the client unexpectedly closed the socket we throw an exception as we didn't get any close message - if (count == 0) - { - throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely); - } - } - finally - { - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, - actionContext, - count); - } - break; - case UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateSendComplete: - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, actionContext, 0); - ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); - await _webSocket._innerStream.FlushAsync().SuppressContextFlow(); - Monitor.Enter(_webSocket.SessionHandle, ref sessionHandleLockTaken); - break; - case UnsafeNativeMethods.WebSocketProtocolComponent.Action.SendToNetwork: - int bytesSent = 0; - try - { - if (_webSocket.State != WebSocketState.CloseSent || - (bufferType != UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.PingPong && - bufferType != UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UnsolicitedPong)) - { - if (dataBufferCount == 0) - { - break; - } - - List> sendBuffers = new List>((int)dataBufferCount); - int sendBufferSize = 0; - ArraySegment framingBuffer = _webSocket._internalBuffer.ConvertNativeBuffer(action, dataBuffers[0], bufferType); - sendBuffers.Add(framingBuffer); - sendBufferSize += framingBuffer.Count; - - // There can be at most 2 dataBuffers - // - one for the framing header and one for the payload - if (dataBufferCount == 2) - { - ArraySegment payload = _webSocket._internalBuffer.ConvertPinnedSendPayloadFromNative(dataBuffers[1], bufferType); - sendBuffers.Add(payload); - sendBufferSize += payload.Count; - } - - ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); - WebSocketHelpers.ThrowIfConnectionAborted(_webSocket._innerStream, false); - await _webSocket.SendFrameAsync(sendBuffers, cancellationToken).SuppressContextFlow(); - Monitor.Enter(_webSocket.SessionHandle, ref sessionHandleLockTaken); - _webSocket.ThrowIfPendingException(); - bytesSent += sendBufferSize; - _webSocket._keepAliveTracker.OnDataSent(); - } - } - finally - { - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, - actionContext, - bytesSent); - } - - break; - default: - string assertMessage = string.Format(CultureInfo.InvariantCulture, - "Invalid action '{0}' returned from WebSocketGetAction.", - action); - Contract.Assert(false, assertMessage); - throw new InvalidOperationException(); - } - } - } - } - finally - { - Cleanup(); - ReleaseLock(_webSocket.SessionHandle, ref sessionHandleLockTaken); - } - - return ReceiveResult; - } - - public class ReceiveOperation : WebSocketOperation - { - private int _receiveState; - private bool _pongReceived; - private bool _receiveCompleted; - - public ReceiveOperation(WebSocketBase webSocket) - : base(webSocket) - { - } - - protected override UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue ActionQueue - { - get { return UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue.Receive; } - } - - protected override int BufferCount - { - get { return 1; } - } - - protected override void Initialize(ArraySegment? buffer, CancellationToken cancellationToken) - { - Contract.Assert(buffer != null, "'buffer' MUST NOT be NULL."); - _pongReceived = false; - _receiveCompleted = false; - _webSocket.ThrowIfDisposed(); - - int originalReceiveState = Interlocked.CompareExchange(ref _webSocket._receiveState, - ReceiveState.Application, ReceiveState.Idle); - - switch (originalReceiveState) - { - case ReceiveState.Idle: - _receiveState = ReceiveState.Application; - break; - case ReceiveState.Application: - Contract.Assert(false, "'originalReceiveState' MUST NEVER be ReceiveState.Application at this point."); - break; - case ReceiveState.PayloadAvailable: - WebSocketReceiveResult receiveResult; - if (!_webSocket._internalBuffer.ReceiveFromBufferedPayload(buffer.Value, out receiveResult)) - { - _webSocket.UpdateReceiveState(ReceiveState.Idle, ReceiveState.PayloadAvailable); - } - ReceiveResult = receiveResult; - _receiveCompleted = true; - break; - default: - Contract.Assert(false, - string.Format(CultureInfo.InvariantCulture, "Invalid ReceiveState '{0}'.", originalReceiveState)); - break; - } - } - - protected override void Cleanup() - { - } - - protected override bool ShouldContinue(CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (_receiveCompleted) - { - return false; - } - - _webSocket.ThrowIfDisposed(); - _webSocket.ThrowIfPendingException(); - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketReceive(_webSocket); - - return true; - } - - protected override bool ProcessAction_NoAction() - { - if (_pongReceived) - { - _receiveCompleted = false; - _pongReceived = false; - return false; - } - - Contract.Assert(ReceiveResult != null, - "'ReceiveResult' MUST NOT be NULL."); - _receiveCompleted = true; - - if (ReceiveResult.MessageType == WebSocketMessageType.Close) - { - return true; - } - - return false; - } - - protected override void ProcessAction_IndicateReceiveComplete( - ArraySegment? buffer, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, - UnsafeNativeMethods.WebSocketProtocolComponent.Action action, - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers, - uint dataBufferCount, - IntPtr actionContext) - { - Contract.Assert(buffer != null, "'buffer MUST NOT be NULL."); - - int bytesTransferred = 0; - _pongReceived = false; - - if (bufferType == UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.PingPong) - { - // ignoring received pong frame - _pongReceived = true; - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, - actionContext, - bytesTransferred); - return; - } - - WebSocketReceiveResult receiveResult; - try - { - ArraySegment payload; - WebSocketMessageType messageType = GetMessageType(bufferType); - int newReceiveState = ReceiveState.Idle; - - if (bufferType == UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close) - { - payload = WebSocketHelpers.EmptyPayload; - string reason; - WebSocketCloseStatus closeStatus; - _webSocket._internalBuffer.ConvertCloseBuffer(action, dataBuffers[0], out closeStatus, out reason); - - receiveResult = new WebSocketReceiveResult(bytesTransferred, - messageType, true, closeStatus, reason); - } - else - { - payload = _webSocket._internalBuffer.ConvertNativeBuffer(action, dataBuffers[0], bufferType); - - bool endOfMessage = bufferType == - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage || - bufferType == UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message || - bufferType == UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close; - - if (payload.Count > buffer.Value.Count) - { - _webSocket._internalBuffer.BufferPayload(payload, buffer.Value.Count, messageType, endOfMessage); - newReceiveState = ReceiveState.PayloadAvailable; - endOfMessage = false; - } - - bytesTransferred = Math.Min(payload.Count, (int)buffer.Value.Count); - if (bytesTransferred > 0) - { - Buffer.BlockCopy(payload.Array, - payload.Offset, - buffer.Value.Array, - buffer.Value.Offset, - bytesTransferred); - } - - receiveResult = new WebSocketReceiveResult(bytesTransferred, messageType, endOfMessage); - } - - _webSocket.UpdateReceiveState(newReceiveState, _receiveState); - } - finally - { - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketCompleteAction(_webSocket, - actionContext, - bytesTransferred); - } - - ReceiveResult = receiveResult; - } - } - - public class SendOperation : WebSocketOperation - { - private bool _completed; - protected bool _bufferHasBeenPinned; - - public SendOperation(WebSocketBase webSocket) - : base(webSocket) - { - } - - protected override UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue ActionQueue - { - get { return UnsafeNativeMethods.WebSocketProtocolComponent.ActionQueue.Send; } - } - - protected override int BufferCount - { - get { return 2; } - } - - protected virtual UnsafeNativeMethods.WebSocketProtocolComponent.Buffer? CreateBuffer(ArraySegment? buffer) - { - if (buffer == null) - { - return null; - } - - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer payloadBuffer; - payloadBuffer = new UnsafeNativeMethods.WebSocketProtocolComponent.Buffer(); - _webSocket._internalBuffer.PinSendBuffer(buffer.Value, out _bufferHasBeenPinned); - payloadBuffer.Data.BufferData = _webSocket._internalBuffer.ConvertPinnedSendPayloadToNative(buffer.Value); - payloadBuffer.Data.BufferLength = (uint)buffer.Value.Count; - return payloadBuffer; - } - - protected override bool ProcessAction_NoAction() - { - _completed = true; - return false; - } - - protected override void Cleanup() - { - if (_bufferHasBeenPinned) - { - _bufferHasBeenPinned = false; - _webSocket._internalBuffer.ReleasePinnedSendBuffer(); - } - } - - internal UnsafeNativeMethods.WebSocketProtocolComponent.BufferType BufferType { get; set; } - - protected override void Initialize(ArraySegment? buffer, - CancellationToken cancellationToken) - { - Contract.Assert(!_bufferHasBeenPinned, "'m_BufferHasBeenPinned' MUST NOT be pinned at this point."); - _webSocket.ThrowIfDisposed(); - _webSocket.ThrowIfPendingException(); - _completed = false; - - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer? payloadBuffer = CreateBuffer(buffer); - if (payloadBuffer != null) - { - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketSend(_webSocket, BufferType, payloadBuffer.Value); - } - else - { - UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketSendWithoutBody(_webSocket, BufferType); - } - } - - protected override bool ShouldContinue(CancellationToken cancellationToken) - { - Contract.Assert(ReceiveResult == null, "'ReceiveResult' MUST be NULL."); - if (_completed) - { - return false; - } - - cancellationToken.ThrowIfCancellationRequested(); - return true; - } - } - - public class CloseOutputOperation : SendOperation - { - public CloseOutputOperation(WebSocketBase webSocket) - : base(webSocket) - { - BufferType = UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close; - } - - internal WebSocketCloseStatus CloseStatus { get; set; } - internal string CloseReason { get; set; } - - protected override UnsafeNativeMethods.WebSocketProtocolComponent.Buffer? CreateBuffer(ArraySegment? buffer) - { - Contract.Assert(buffer == null, "'buffer' MUST BE NULL."); - _webSocket.ThrowIfDisposed(); - _webSocket.ThrowIfPendingException(); - - if (CloseStatus == WebSocketCloseStatus.Empty) - { - return null; - } - - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer payloadBuffer = new UnsafeNativeMethods.WebSocketProtocolComponent.Buffer(); - if (CloseReason != null) - { - byte[] blob = UTF8Encoding.UTF8.GetBytes(CloseReason); - Contract.Assert(blob.Length <= WebSocketHelpers.MaxControlFramePayloadLength, - "The close reason is too long."); - ArraySegment closeBuffer = new ArraySegment(blob, 0, Math.Min(WebSocketHelpers.MaxControlFramePayloadLength, blob.Length)); - _webSocket._internalBuffer.PinSendBuffer(closeBuffer, out _bufferHasBeenPinned); - payloadBuffer.CloseStatus.ReasonData = _webSocket._internalBuffer.ConvertPinnedSendPayloadToNative(closeBuffer); - payloadBuffer.CloseStatus.ReasonLength = (uint)closeBuffer.Count; - } - - payloadBuffer.CloseStatus.CloseStatus = (ushort)CloseStatus; - return payloadBuffer; - } - } - } - - private abstract class KeepAliveTracker : IDisposable - { - // Multi-Threading: only one thread at a time is allowed to call OnDataReceived or OnDataSent - // - but both methods can be called from different threads at the same time. - public abstract void OnDataReceived(); - public abstract void OnDataSent(); - public abstract void Dispose(); - public abstract void StartTimer(WebSocketBase webSocket); - public abstract void ResetTimer(); - public abstract bool ShouldSendKeepAlive(); - - public static KeepAliveTracker Create(TimeSpan keepAliveInterval) - { - if ((int)keepAliveInterval.TotalMilliseconds > 0) - { - return new DefaultKeepAliveTracker(keepAliveInterval); - } - - return new DisabledKeepAliveTracker(); - } - - private class DisabledKeepAliveTracker : KeepAliveTracker - { - public override void OnDataReceived() - { - } - - public override void OnDataSent() - { - } - - public override void ResetTimer() - { - } - - public override void StartTimer(WebSocketBase webSocket) - { - } - - public override bool ShouldSendKeepAlive() - { - return false; - } - - public override void Dispose() - { - } - } - - private class DefaultKeepAliveTracker : KeepAliveTracker - { - private static readonly TimerCallback _keepAliveTimerElapsedCallback = new TimerCallback(OnKeepAlive); - private readonly TimeSpan _keepAliveInterval; - private readonly Stopwatch _lastSendActivity; - private readonly Stopwatch _lastReceiveActivity; - private Timer _keepAliveTimer; - - public DefaultKeepAliveTracker(TimeSpan keepAliveInterval) - { - _keepAliveInterval = keepAliveInterval; - _lastSendActivity = new Stopwatch(); - _lastReceiveActivity = new Stopwatch(); - } - - public override void OnDataReceived() - { - _lastReceiveActivity.Restart(); - } - - public override void OnDataSent() - { - _lastSendActivity.Restart(); - } - - public override void ResetTimer() - { - ResetTimer((int)_keepAliveInterval.TotalMilliseconds); - } - - public override void StartTimer(WebSocketBase webSocket) - { - Contract.Assert(webSocket != null, "'webSocket' MUST NOT be NULL."); - Contract.Assert(webSocket._keepAliveTracker != null, - "'webSocket.m_KeepAliveTracker' MUST NOT be NULL at this point."); - int keepAliveIntervalMilliseconds = (int)_keepAliveInterval.TotalMilliseconds; - Contract.Assert(keepAliveIntervalMilliseconds > 0, "'keepAliveIntervalMilliseconds' MUST be POSITIVE."); -#if NETSTANDARD1_3 - _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); -#else - if (ExecutionContext.IsFlowSuppressed()) - { - _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); - } - else - { - using (ExecutionContext.SuppressFlow()) - { - _keepAliveTimer = new Timer(_keepAliveTimerElapsedCallback, webSocket, keepAliveIntervalMilliseconds, Timeout.Infinite); - } - } -#endif - } - - public override bool ShouldSendKeepAlive() - { - TimeSpan idleTime = GetIdleTime(); - if (idleTime >= _keepAliveInterval) - { - return true; - } - - ResetTimer((int)(_keepAliveInterval - idleTime).TotalMilliseconds); - return false; - } - - public override void Dispose() - { - _keepAliveTimer.Dispose(); - } - - private void ResetTimer(int dueInMilliseconds) - { - _keepAliveTimer.Change(dueInMilliseconds, Timeout.Infinite); - } - - private TimeSpan GetIdleTime() - { - TimeSpan sinceLastSendActivity = GetTimeElapsed(_lastSendActivity); - TimeSpan sinceLastReceiveActivity = GetTimeElapsed(_lastReceiveActivity); - - if (sinceLastReceiveActivity < sinceLastSendActivity) - { - return sinceLastReceiveActivity; - } - - return sinceLastSendActivity; - } - - private TimeSpan GetTimeElapsed(Stopwatch watch) - { - if (watch.IsRunning) - { - return watch.Elapsed; - } - - return _keepAliveInterval; - } - } - } - - private class OutstandingOperationHelper : IDisposable - { - private volatile int _operationsOutstanding; - private volatile CancellationTokenSource _cancellationTokenSource; - private volatile bool _isDisposed; - private readonly object _thisLock = new object(); - - public bool TryStartOperation(CancellationToken userCancellationToken, out CancellationToken linkedCancellationToken) - { - linkedCancellationToken = CancellationToken.None; - ThrowIfDisposed(); - - lock (_thisLock) - { - int operationsOutstanding = ++_operationsOutstanding; - - if (operationsOutstanding == 1) - { - linkedCancellationToken = CreateLinkedCancellationToken(userCancellationToken); - return true; - } - - Contract.Assert(operationsOutstanding >= 1, "'operationsOutstanding' must never be smaller than 1."); - return false; - } - } - - public void CompleteOperation(bool ownsCancellationTokenSource) - { - if (_isDisposed) - { - // no-op if the WebSocket is already aborted - return; - } - - CancellationTokenSource snapshot = null; - - lock (_thisLock) - { - --_operationsOutstanding; - Contract.Assert(_operationsOutstanding >= 0, "'m_OperationsOutstanding' must never be smaller than 0."); - - if (ownsCancellationTokenSource) - { - snapshot = _cancellationTokenSource; - _cancellationTokenSource = null; - } - } - - if (snapshot != null) - { - snapshot.Dispose(); - } - } - - // Has to be called under m_ThisLock lock - private CancellationToken CreateLinkedCancellationToken(CancellationToken cancellationToken) - { - CancellationTokenSource linkedCancellationTokenSource; - - if (cancellationToken == CancellationToken.None) - { - linkedCancellationTokenSource = new CancellationTokenSource(); - } - else - { - linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, - new CancellationTokenSource().Token); - } - - Contract.Assert(_cancellationTokenSource == null, "'m_CancellationTokenSource' MUST be NULL."); - _cancellationTokenSource = linkedCancellationTokenSource; - - return linkedCancellationTokenSource.Token; - } - - public void CancelIO() - { - CancellationTokenSource cancellationTokenSourceSnapshot = null; - - lock (_thisLock) - { - if (_operationsOutstanding == 0) - { - return; - } - - cancellationTokenSourceSnapshot = _cancellationTokenSource; - } - - if (cancellationTokenSourceSnapshot != null) - { - try - { - cancellationTokenSourceSnapshot.Cancel(); - } - catch (ObjectDisposedException) - { - // Simply ignore this exception - There is apparently a rare race condition - // where the cancellationTokensource is disposed before the Cancel method call completed. - } - } - } - - public void Dispose() - { - if (_isDisposed) - { - return; - } - - CancellationTokenSource snapshot = null; - lock (_thisLock) - { - if (_isDisposed) - { - return; - } - - _isDisposed = true; - snapshot = _cancellationTokenSource; - _cancellationTokenSource = null; - } - - if (snapshot != null) - { - snapshot.Dispose(); - } - } - - private void ThrowIfDisposed() - { - if (_isDisposed) - { - throw new ObjectDisposedException(GetType().FullName); - } - } - } - - internal interface IWebSocketStream - { - // Switching to opaque mode will change the behavior to use the knowledge that the WebSocketBase class - // is pinning all payloads already and that we will have at most one outstanding send and receive at any - // given time. This allows us to avoid creation of OverlappedData and pinning for each operation. - - void SwitchToOpaqueMode(WebSocketBase webSocket); - void Abort(); - bool SupportsMultipleWrite { get; } - Task MultipleWriteAsync(IList> buffers, CancellationToken cancellationToken); - - // Any implementation has to guarantee that no exception is thrown synchronously - // for example by enforcing a Task.Yield at the beginning of the method - // This is necessary to enforce an API contract (for WebSocketBase.StartOnCloseCompleted) that ensures - // that all locks have been released whenever an exception is thrown from it. - Task CloseNetworkConnectionAsync(CancellationToken cancellationToken); - } - - private static class ReceiveState - { - internal const int SendOperation = -1; - internal const int Idle = 0; - internal const int Application = 1; - internal const int PayloadAvailable = 2; - } - - internal static class Methods - { - internal const string ReceiveAsync = "ReceiveAsync"; - internal const string SendAsync = "SendAsync"; - internal const string CloseAsync = "CloseAsync"; - internal const string CloseOutputAsync = "CloseOutputAsync"; - internal const string Abort = "Abort"; - internal const string Initialize = "Initialize"; - internal const string Fault = "Fault"; - internal const string StartOnCloseCompleted = "StartOnCloseCompleted"; - internal const string FinishOnCloseReceived = "FinishOnCloseReceived"; - internal const string OnKeepAlive = "OnKeepAlive"; - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs deleted file mode 100644 index 1c87e73334..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketBuffer.cs +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using System.Globalization; -using System.Net.WebSockets; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; - -namespace Microsoft.Net.WebSockets -{ - // This class helps to abstract the internal WebSocket buffer, which is used to interact with the native WebSocket - // protocol component (WSPC). It helps to shield the details of the layout and the involved pointer arithmetic. - // The internal WebSocket buffer also contains a segment, which is used by the WebSocketBase class to buffer - // payload (parsed by WSPC already) for the application, if the application requested fewer bytes than the - // WSPC returned. The internal buffer is pinned for the whole lifetime if this class. - // LAYOUT: - // | Native buffer | PayloadReceiveBuffer | PropertyBuffer | - // | RBS + SBS + 144 | RBS | PBS | - // | Only WSPC may modify | Only WebSocketBase may modify | - // - // *RBS = ReceiveBufferSize, *SBS = SendBufferSize - // *PBS = PropertyBufferSize (32-bit: 16, 64 bit: 20 bytes) - public class WebSocketBuffer : IDisposable - { - private const int NativeOverheadBufferSize = 144; - public const int MinSendBufferSize = 16; - internal const int MinReceiveBufferSize = 256; - internal const int MaxBufferSize = 64 * 1024; - private static readonly int SizeOfUInt = Marshal.SizeOf(); - private static readonly int SizeOfBool = Marshal.SizeOf(); - private static readonly int PropertyBufferSize = (2 * SizeOfUInt) + SizeOfBool + IntPtr.Size; - - private readonly int _ReceiveBufferSize; - - // Indicates the range of the pinned byte[] that can be used by the WSPC (nativeBuffer + pinnedSendBuffer) - private readonly long _StartAddress; - private readonly long _EndAddress; - private readonly GCHandle _GCHandle; - private readonly ArraySegment _InternalBuffer; - private readonly ArraySegment _NativeBuffer; - private readonly ArraySegment _PayloadBuffer; - private readonly ArraySegment _PropertyBuffer; - private readonly int _SendBufferSize; - private volatile int _PayloadOffset; - private WebSocketReceiveResult _BufferedPayloadReceiveResult; - private long _PinnedSendBufferStartAddress; - private long _PinnedSendBufferEndAddress; - private ArraySegment _PinnedSendBuffer; - private GCHandle _PinnedSendBufferHandle; - private int _StateWhenDisposing = int.MinValue; - private int _SendBufferState; - - private WebSocketBuffer(ArraySegment internalBuffer, int receiveBufferSize, int sendBufferSize) - { - Contract.Assert(internalBuffer.Array != null, "'internalBuffer' MUST NOT be NULL."); - Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, - "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - Contract.Assert(sendBufferSize >= MinSendBufferSize, - "'sendBufferSize' MUST be at least " + MinSendBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - Contract.Assert(receiveBufferSize <= MaxBufferSize, - "'receiveBufferSize' MUST NOT exceed " + MaxBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - Contract.Assert(sendBufferSize <= MaxBufferSize, - "'sendBufferSize' MUST NOT exceed " + MaxBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - - _ReceiveBufferSize = receiveBufferSize; - _SendBufferSize = sendBufferSize; - _InternalBuffer = internalBuffer; - _GCHandle = GCHandle.Alloc(internalBuffer.Array, GCHandleType.Pinned); - // Size of the internal buffer owned exclusively by the WSPC. - int nativeBufferSize = _ReceiveBufferSize + _SendBufferSize + NativeOverheadBufferSize; - _StartAddress = Marshal.UnsafeAddrOfPinnedArrayElement(internalBuffer.Array, internalBuffer.Offset).ToInt64(); - _EndAddress = _StartAddress + nativeBufferSize; - _NativeBuffer = new ArraySegment(internalBuffer.Array, internalBuffer.Offset, nativeBufferSize); - _PayloadBuffer = new ArraySegment(internalBuffer.Array, - _NativeBuffer.Offset + _NativeBuffer.Count, - _ReceiveBufferSize); - _PropertyBuffer = new ArraySegment(internalBuffer.Array, - _PayloadBuffer.Offset + _PayloadBuffer.Count, - PropertyBufferSize); - _SendBufferState = SendBufferState.None; - } - - public int ReceiveBufferSize - { - get { return _ReceiveBufferSize; } - } - - public int SendBufferSize - { - get { return _SendBufferSize; } - } - - internal static WebSocketBuffer CreateClientBuffer(ArraySegment internalBuffer, int receiveBufferSize, int sendBufferSize) - { - Contract.Assert(internalBuffer.Count >= GetInternalBufferSize(receiveBufferSize, sendBufferSize, false), - "Array 'internalBuffer' is TOO SMALL. Call Validate before instantiating WebSocketBuffer."); - - return new WebSocketBuffer(internalBuffer, receiveBufferSize, GetNativeSendBufferSize(sendBufferSize, false)); - } - - internal static WebSocketBuffer CreateServerBuffer(ArraySegment internalBuffer, int receiveBufferSize) - { - int sendBufferSize = GetNativeSendBufferSize(MinSendBufferSize, true); - Contract.Assert(internalBuffer.Count >= GetInternalBufferSize(receiveBufferSize, sendBufferSize, true), - "Array 'internalBuffer' is TOO SMALL. Call Validate before instantiating WebSocketBuffer."); - - return new WebSocketBuffer(internalBuffer, receiveBufferSize, sendBufferSize); - } - - public void Dispose(WebSocketState webSocketState) - { - if (Interlocked.CompareExchange(ref _StateWhenDisposing, (int)webSocketState, int.MinValue) != int.MinValue) - { - return; - } - - this.CleanUp(); - } - - public void Dispose() - { - this.Dispose(WebSocketState.None); - } - - internal UnsafeNativeMethods.WebSocketProtocolComponent.Property[] CreateProperties(bool useZeroMaskingKey) - { - ThrowIfDisposed(); - // serialize marshaled property values in the property segment of the internal buffer - IntPtr internalBufferPtr = _GCHandle.AddrOfPinnedObject(); - int offset = _PropertyBuffer.Offset; - Marshal.WriteInt32(internalBufferPtr, offset, _ReceiveBufferSize); - offset += SizeOfUInt; - Marshal.WriteInt32(internalBufferPtr, offset, _SendBufferSize); - offset += SizeOfUInt; - Marshal.WriteIntPtr(internalBufferPtr, offset, internalBufferPtr); - offset += IntPtr.Size; - Marshal.WriteInt32(internalBufferPtr, offset, useZeroMaskingKey ? (int)1 : (int)0); - - int propertyCount = useZeroMaskingKey ? 4 : 3; - UnsafeNativeMethods.WebSocketProtocolComponent.Property[] properties = - new UnsafeNativeMethods.WebSocketProtocolComponent.Property[propertyCount]; - - // Calculate the pointers to the positions of the properties within the internal buffer - offset = _PropertyBuffer.Offset; - properties[0] = new UnsafeNativeMethods.WebSocketProtocolComponent.Property() - { - Type = UnsafeNativeMethods.WebSocketProtocolComponent.PropertyType.ReceiveBufferSize, - PropertySize = (uint)SizeOfUInt, - PropertyData = IntPtr.Add(internalBufferPtr, offset) - }; - offset += SizeOfUInt; - - properties[1] = new UnsafeNativeMethods.WebSocketProtocolComponent.Property() - { - Type = UnsafeNativeMethods.WebSocketProtocolComponent.PropertyType.SendBufferSize, - PropertySize = (uint)SizeOfUInt, - PropertyData = IntPtr.Add(internalBufferPtr, offset) - }; - offset += SizeOfUInt; - - properties[2] = new UnsafeNativeMethods.WebSocketProtocolComponent.Property() - { - Type = UnsafeNativeMethods.WebSocketProtocolComponent.PropertyType.AllocatedBuffer, - PropertySize = (uint)_NativeBuffer.Count, - PropertyData = IntPtr.Add(internalBufferPtr, offset) - }; - offset += IntPtr.Size; - - if (useZeroMaskingKey) - { - properties[3] = new UnsafeNativeMethods.WebSocketProtocolComponent.Property() - { - Type = UnsafeNativeMethods.WebSocketProtocolComponent.PropertyType.DisableMasking, - PropertySize = (uint)SizeOfBool, - PropertyData = IntPtr.Add(internalBufferPtr, offset) - }; - } - - return properties; - } - - // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation - internal void PinSendBuffer(ArraySegment payload, out bool bufferHasBeenPinned) - { - bufferHasBeenPinned = false; - WebSocketHelpers.ValidateBuffer(payload.Array, payload.Offset, payload.Count); - int previousState = Interlocked.Exchange(ref _SendBufferState, SendBufferState.SendPayloadSpecified); - - if (previousState != SendBufferState.None) - { - Contract.Assert(false, "'m_SendBufferState' MUST BE 'None' at this point."); - // Indicates a violation in the API contract that could indicate - // memory corruption because the pinned sendbuffer is shared between managed and native code - throw new AccessViolationException(); - } - _PinnedSendBuffer = payload; - _PinnedSendBufferHandle = GCHandle.Alloc(_PinnedSendBuffer.Array, GCHandleType.Pinned); - bufferHasBeenPinned = true; - _PinnedSendBufferStartAddress = - Marshal.UnsafeAddrOfPinnedArrayElement(_PinnedSendBuffer.Array, _PinnedSendBuffer.Offset).ToInt64(); - _PinnedSendBufferEndAddress = _PinnedSendBufferStartAddress + _PinnedSendBuffer.Count; - } - - // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation - internal IntPtr ConvertPinnedSendPayloadToNative(ArraySegment payload) - { - return ConvertPinnedSendPayloadToNative(payload.Array, payload.Offset, payload.Count); - } - - // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation - internal IntPtr ConvertPinnedSendPayloadToNative(byte[] buffer, int offset, int count) - { - if (!IsPinnedSendPayloadBuffer(buffer, offset, count)) - { - // Indicates a violation in the API contract that could indicate - // memory corruption because the pinned sendbuffer is shared between managed and native code - throw new AccessViolationException(); - } - - Contract.Assert(Marshal.UnsafeAddrOfPinnedArrayElement(_PinnedSendBuffer.Array, - _PinnedSendBuffer.Offset).ToInt64() == _PinnedSendBufferStartAddress, - "'m_PinnedSendBuffer.Array' MUST be pinned during the entire send operation."); - - return new IntPtr(_PinnedSendBufferStartAddress + offset - _PinnedSendBuffer.Offset); - } - - // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation - internal ArraySegment ConvertPinnedSendPayloadFromNative(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType) - { - if (!IsPinnedSendPayloadBuffer(buffer, bufferType)) - { - // Indicates a violation in the API contract that could indicate - // memory corruption because the pinned sendbuffer is shared between managed and native code - throw new AccessViolationException(); - } - - Contract.Assert(Marshal.UnsafeAddrOfPinnedArrayElement(_PinnedSendBuffer.Array, - _PinnedSendBuffer.Offset).ToInt64() == _PinnedSendBufferStartAddress, - "'m_PinnedSendBuffer.Array' MUST be pinned during the entire send operation."); - - IntPtr bufferData; - uint bufferSize; - - UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferSize); - - int internalOffset = (int)(bufferData.ToInt64() - _PinnedSendBufferStartAddress); - - return new ArraySegment(_PinnedSendBuffer.Array, _PinnedSendBuffer.Offset + internalOffset, (int)bufferSize); - } - - // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation - private bool IsPinnedSendPayloadBuffer(byte[] buffer, int offset, int count) - { - if (_SendBufferState != SendBufferState.SendPayloadSpecified) - { - return false; - } - - return object.ReferenceEquals(buffer, _PinnedSendBuffer.Array) && - offset >= _PinnedSendBuffer.Offset && - offset + count <= _PinnedSendBuffer.Offset + _PinnedSendBuffer.Count; - } - - // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation - private bool IsPinnedSendPayloadBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType) - { - if (_SendBufferState != SendBufferState.SendPayloadSpecified) - { - return false; - } - - IntPtr bufferData; - uint bufferSize; - - UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferSize); - - long nativeBufferStartAddress = bufferData.ToInt64(); - long nativeBufferEndAddress = nativeBufferStartAddress + bufferSize; - - return nativeBufferStartAddress >= _PinnedSendBufferStartAddress && - nativeBufferEndAddress >= _PinnedSendBufferStartAddress && - nativeBufferStartAddress <= _PinnedSendBufferEndAddress && - nativeBufferEndAddress <= _PinnedSendBufferEndAddress; - } - - // This method is only thread safe for races between Abort and at most 1 uncompleted send operation - internal void ReleasePinnedSendBuffer() - { - int previousState = Interlocked.Exchange(ref _SendBufferState, SendBufferState.None); - - if (previousState != SendBufferState.SendPayloadSpecified) - { - return; - } - - if (_PinnedSendBufferHandle.IsAllocated) - { - _PinnedSendBufferHandle.Free(); - } - - _PinnedSendBuffer = WebSocketHelpers.EmptyPayload; - } - - internal void BufferPayload(ArraySegment payload, - int unconsumedDataOffset, - WebSocketMessageType messageType, - bool endOfMessage) - { - ThrowIfDisposed(); - int bytesBuffered = payload.Count - unconsumedDataOffset; - - Contract.Assert(_PayloadOffset == 0, - "'m_PayloadOffset' MUST be '0' at this point."); - Contract.Assert(_BufferedPayloadReceiveResult == null || _BufferedPayloadReceiveResult.Count == 0, - "'m_BufferedPayloadReceiveResult.Count' MUST be '0' at this point."); - - Buffer.BlockCopy(payload.Array, - payload.Offset + unconsumedDataOffset, - _PayloadBuffer.Array, - _PayloadBuffer.Offset, - bytesBuffered); - - _BufferedPayloadReceiveResult = - new WebSocketReceiveResult(bytesBuffered, messageType, endOfMessage); - - this.ValidateBufferedPayload(); - } - - internal bool ReceiveFromBufferedPayload(ArraySegment buffer, out WebSocketReceiveResult receiveResult) - { - ThrowIfDisposed(); - ValidateBufferedPayload(); - - int bytesTransferred = Math.Min(buffer.Count, _BufferedPayloadReceiveResult.Count); - receiveResult = WebSocketReceiveResultExtensions.DecrementAndClone(ref _BufferedPayloadReceiveResult, bytesTransferred); - - Buffer.BlockCopy(_PayloadBuffer.Array, - _PayloadBuffer.Offset + _PayloadOffset, - buffer.Array, - buffer.Offset, - bytesTransferred); - - bool morePayloadBuffered; - if (_BufferedPayloadReceiveResult.Count == 0) - { - _PayloadOffset = 0; - _BufferedPayloadReceiveResult = null; - morePayloadBuffered = false; - } - else - { - _PayloadOffset += bytesTransferred; - morePayloadBuffered = true; - this.ValidateBufferedPayload(); - } - - return morePayloadBuffered; - } - - internal ArraySegment ConvertNativeBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Action action, - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType) - { - ThrowIfDisposed(); - - IntPtr bufferData; - uint bufferLength; - - UnwrapWebSocketBuffer(buffer, bufferType, out bufferData, out bufferLength); - - if (bufferData == IntPtr.Zero) - { - return WebSocketHelpers.EmptyPayload; - } - - if (this.IsNativeBuffer(bufferData, bufferLength)) - { - return new ArraySegment(_InternalBuffer.Array, - this.GetOffset(bufferData), - (int)bufferLength); - } - - Contract.Assert(false, "'buffer' MUST reference a memory segment within the pinned InternalBuffer."); - // Indicates a violation in the contract with native Websocket.dll and could indicate - // memory corruption because the internal buffer is shared between managed and native code - throw new AccessViolationException(); - } - - internal void ConvertCloseBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Action action, - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, - out WebSocketCloseStatus closeStatus, - out string reason) - { - ThrowIfDisposed(); - IntPtr bufferData; - uint bufferLength; - closeStatus = (WebSocketCloseStatus)buffer.CloseStatus.CloseStatus; - - UnwrapWebSocketBuffer(buffer, UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close, out bufferData, out bufferLength); - - if (bufferData == IntPtr.Zero) - { - reason = null; - } - else - { - ArraySegment reasonBlob; - if (this.IsNativeBuffer(bufferData, bufferLength)) - { - reasonBlob = new ArraySegment(_InternalBuffer.Array, - this.GetOffset(bufferData), - (int)bufferLength); - } - else - { - Contract.Assert(false, "'buffer' MUST reference a memory segment within the pinned InternalBuffer."); - // Indicates a violation in the contract with native Websocket.dll and could indicate - // memory corruption because the internal buffer is shared between managed and native code - throw new AccessViolationException(); - } - - // No need to wrap DecoderFallbackException for invalid UTF8 chacters, because - // Encoding.UTF8 will not throw but replace invalid characters instead. - reason = Encoding.UTF8.GetString(reasonBlob.Array, reasonBlob.Offset, reasonBlob.Count); - } - } - - internal void ValidateNativeBuffers(UnsafeNativeMethods.WebSocketProtocolComponent.Action action, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer[] dataBuffers, - uint dataBufferCount) - { - Contract.Assert(dataBufferCount <= (uint)int.MaxValue, - "'dataBufferCount' MUST NOT be bigger than Int32.MaxValue."); - Contract.Assert(dataBuffers != null, "'dataBuffers' MUST NOT be NULL."); - - ThrowIfDisposed(); - if (dataBufferCount > dataBuffers.Length) - { - Contract.Assert(false, "'dataBufferCount' MUST NOT be bigger than 'dataBuffers.Length'."); - // Indicates a violation in the contract with native Websocket.dll and could indicate - // memory corruption because the internal buffer is shared between managed and native code - throw new AccessViolationException(); - } - - int count = dataBuffers.Length; - bool isSendActivity = action == UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateSendComplete || - action == UnsafeNativeMethods.WebSocketProtocolComponent.Action.SendToNetwork; - - if (isSendActivity) - { - count = (int)dataBufferCount; - } - - bool nonZeroBufferFound = false; - for (int i = 0; i < count; i++) - { - UnsafeNativeMethods.WebSocketProtocolComponent.Buffer dataBuffer = dataBuffers[i]; - - IntPtr bufferData; - uint bufferLength; - UnwrapWebSocketBuffer(dataBuffer, bufferType, out bufferData, out bufferLength); - - if (bufferData == IntPtr.Zero) - { - continue; - } - - nonZeroBufferFound = true; - - bool isPinnedSendPayloadBuffer = IsPinnedSendPayloadBuffer(dataBuffer, bufferType); - - if (bufferLength > GetMaxBufferSize()) - { - if (!isSendActivity || !isPinnedSendPayloadBuffer) - { - Contract.Assert(false, - "'dataBuffer.BufferLength' MUST NOT be bigger than 'm_ReceiveBufferSize' and 'm_SendBufferSize'."); - // Indicates a violation in the contract with native Websocket.dll and could indicate - // memory corruption because the internal buffer is shared between managed and native code - throw new AccessViolationException(); - } - } - - if (!isPinnedSendPayloadBuffer && !IsNativeBuffer(bufferData, bufferLength)) - { - Contract.Assert(false, - "WebSocketGetAction MUST return a pointer within the pinned internal buffer."); - // Indicates a violation in the contract with native Websocket.dll and could indicate - // memory corruption because the internal buffer is shared between managed and native code - throw new AccessViolationException(); - } - } - - if (!nonZeroBufferFound && - action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.NoAction && - action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateReceiveComplete && - action != UnsafeNativeMethods.WebSocketProtocolComponent.Action.IndicateSendComplete) - { - Contract.Assert(false, "At least one 'dataBuffer.Buffer' MUST NOT be NULL."); - } - } - - private static int GetNativeSendBufferSize(int sendBufferSize, bool isServerBuffer) - { - return isServerBuffer ? MinSendBufferSize : sendBufferSize; - } - - internal static void UnwrapWebSocketBuffer(UnsafeNativeMethods.WebSocketProtocolComponent.Buffer buffer, - UnsafeNativeMethods.WebSocketProtocolComponent.BufferType bufferType, - out IntPtr bufferData, - out uint bufferLength) - { - bufferData = IntPtr.Zero; - bufferLength = 0; - - switch (bufferType) - { - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.Close: - bufferData = buffer.CloseStatus.ReasonData; - bufferLength = buffer.CloseStatus.ReasonLength; - break; - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.None: - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryFragment: - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.BinaryMessage: - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Fragment: - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UTF8Message: - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.PingPong: - case UnsafeNativeMethods.WebSocketProtocolComponent.BufferType.UnsolicitedPong: - bufferData = buffer.Data.BufferData; - bufferLength = buffer.Data.BufferLength; - break; - default: - Contract.Assert(false, - string.Format(CultureInfo.InvariantCulture, - "BufferType '{0}' is invalid/unknown.", - bufferType)); - break; - } - } - - private void ThrowIfDisposed() - { - switch (_StateWhenDisposing) - { - case int.MinValue: - return; - case (int)WebSocketState.Closed: - case (int)WebSocketState.Aborted: - throw new WebSocketException(WebSocketError.InvalidState, - SR.GetString(SR.net_WebSockets_InvalidState_ClosedOrAborted, typeof(WebSocketBase), _StateWhenDisposing)); - default: - throw new ObjectDisposedException(GetType().FullName); - } - } - - [Conditional("DEBUG"), Conditional("CONTRACTS_FULL")] - private void ValidateBufferedPayload() - { - Contract.Assert(_BufferedPayloadReceiveResult != null, - "'m_BufferedPayloadReceiveResult' MUST NOT be NULL."); - Contract.Assert(_BufferedPayloadReceiveResult.Count >= 0, - "'m_BufferedPayloadReceiveResult.Count' MUST NOT be negative."); - Contract.Assert(_PayloadOffset >= 0, "'m_PayloadOffset' MUST NOT be smaller than 0."); - Contract.Assert(_PayloadOffset <= _PayloadBuffer.Count, - "'m_PayloadOffset' MUST NOT be bigger than 'm_PayloadBuffer.Count'."); - Contract.Assert(_PayloadOffset + _BufferedPayloadReceiveResult.Count <= _PayloadBuffer.Count, - "'m_PayloadOffset + m_PayloadBytesBuffered' MUST NOT be bigger than 'm_PayloadBuffer.Count'."); - } - - private int GetOffset(IntPtr pBuffer) - { - Contract.Assert(pBuffer != IntPtr.Zero, "'pBuffer' MUST NOT be IntPtr.Zero."); - int offset = (int)(pBuffer.ToInt64() - _StartAddress + _InternalBuffer.Offset); - - Contract.Assert(offset >= 0, "'offset' MUST NOT be negative."); - return offset; - } - - [Pure] - private int GetMaxBufferSize() - { - return Math.Max(_ReceiveBufferSize, _SendBufferSize); - } - - internal bool IsInternalBuffer(byte[] buffer, int offset, int count) - { - Contract.Assert(buffer != null, "'buffer' MUST NOT be NULL."); - Contract.Assert(_InternalBuffer.Array != null, "'m_InternalBuffer.Array' MUST NOT be NULL."); - Contract.Assert(offset >= 0, "'offset' MUST NOT be negative."); - Contract.Assert(count >= 0, "'count' MUST NOT be negative."); - Contract.Assert(offset + count <= buffer.Length, "'offset + count' MUST NOT exceed 'buffer.Length'."); - - return object.ReferenceEquals(buffer, _InternalBuffer.Array); - } - - internal IntPtr ToIntPtr(int offset) - { - Contract.Assert(offset >= 0, "'offset' MUST NOT be negative."); - Contract.Assert(_StartAddress + offset <= _EndAddress, "'offset' is TOO BIG."); - return new IntPtr(_StartAddress + offset); - } - - private bool IsNativeBuffer(IntPtr pBuffer, uint bufferSize) - { - Contract.Assert(pBuffer != IntPtr.Zero, "'pBuffer' MUST NOT be NULL."); - Contract.Assert(bufferSize <= GetMaxBufferSize(), - "'bufferSize' MUST NOT be bigger than 'm_ReceiveBufferSize' and 'm_SendBufferSize'."); - - long nativeBufferStartAddress = pBuffer.ToInt64(); - long nativeBufferEndAddress = bufferSize + nativeBufferStartAddress; - - Contract.Assert(Marshal.UnsafeAddrOfPinnedArrayElement(_InternalBuffer.Array, _InternalBuffer.Offset).ToInt64() == _StartAddress, - "'m_InternalBuffer.Array' MUST be pinned for the whole lifetime of a WebSocket."); - - if (nativeBufferStartAddress >= _StartAddress && - nativeBufferStartAddress <= _EndAddress && - nativeBufferEndAddress >= _StartAddress && - nativeBufferEndAddress <= _EndAddress) - { - return true; - } - - return false; - } - - private void CleanUp() - { - if (_GCHandle.IsAllocated) - { - _GCHandle.Free(); - } - - ReleasePinnedSendBuffer(); - } - - public static ArraySegment CreateInternalBufferArraySegment(int receiveBufferSize, int sendBufferSize, bool isServerBuffer) - { - Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, - "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - Contract.Assert(sendBufferSize >= MinSendBufferSize, - "'sendBufferSize' MUST be at least " + MinSendBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - - int internalBufferSize = GetInternalBufferSize(receiveBufferSize, sendBufferSize, isServerBuffer); - return new ArraySegment(new byte[internalBufferSize]); - } - - public static void Validate(int count, int receiveBufferSize, int sendBufferSize, bool isServerBuffer) - { - Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, - "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - Contract.Assert(sendBufferSize >= MinSendBufferSize, - "'sendBufferSize' MUST be at least " + MinSendBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - - int minBufferSize = GetInternalBufferSize(receiveBufferSize, sendBufferSize, isServerBuffer); - if (count < minBufferSize) - { - throw new ArgumentOutOfRangeException("internalBuffer", - SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_InternalBuffer, minBufferSize)); - } - } - - private static int GetInternalBufferSize(int receiveBufferSize, int sendBufferSize, bool isServerBuffer) - { - Contract.Assert(receiveBufferSize >= MinReceiveBufferSize, - "'receiveBufferSize' MUST be at least " + MinReceiveBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - Contract.Assert(sendBufferSize >= MinSendBufferSize, - "'sendBufferSize' MUST be at least " + MinSendBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - - Contract.Assert(receiveBufferSize <= MaxBufferSize, - "'receiveBufferSize' MUST be less than or equal to " + MaxBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - Contract.Assert(sendBufferSize <= MaxBufferSize, - "'sendBufferSize' MUST be at less than or equal to " + MaxBufferSize.ToString(NumberFormatInfo.InvariantInfo) + "."); - - int nativeSendBufferSize = GetNativeSendBufferSize(sendBufferSize, isServerBuffer); - return (2 * receiveBufferSize) + nativeSendBufferSize + NativeOverheadBufferSize + PropertyBufferSize; - } - - private static class SendBufferState - { - public const int None = 0; - public const int SendPayloadSpecified = 1; - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketConstants.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketConstants.cs deleted file mode 100644 index c5aa4d8a85..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketConstants.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Microsoft.Net.WebSockets -{ - public static class WebSocketConstants - { - public static string SupportedProtocolVersion = "13"; - } -} \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketError.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketError.cs deleted file mode 100644 index 09811b81c9..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketError.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.Net.WebSockets -{ - internal enum WebSocketError - { - Success = 0, - InvalidMessageType = 1, - Faulted = 2, - NativeError = 3, - NotAWebSocket = 4, - UnsupportedVersion = 5, - UnsupportedProtocol = 6, - HeaderError = 7, - ConnectionClosedPrematurely = 8, - InvalidState = 9 - } -} \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs deleted file mode 100644 index a906a5d6aa..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketException.cs +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.ComponentModel; -using System.Net.WebSockets; -using System.Runtime.InteropServices; - -namespace Microsoft.Net.WebSockets -{ -#if !NETSTANDARD1_3 - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] -#endif - internal sealed class WebSocketException : Win32Exception - { - private WebSocketError _WebSocketErrorCode; - - public WebSocketException() - : this(Marshal.GetLastWin32Error()) - { - } - - public WebSocketException(WebSocketError error) - : this(error, GetErrorMessage(error)) - { - } - - public WebSocketException(WebSocketError error, string message) : base(message) - { - _WebSocketErrorCode = error; - } - - public WebSocketException(WebSocketError error, Exception innerException) - : this(error, GetErrorMessage(error), innerException) - { - } - - public WebSocketException(WebSocketError error, string message, Exception innerException) - : base(message, innerException) - { - _WebSocketErrorCode = error; - } - - public WebSocketException(int nativeError) - : base(nativeError) - { - _WebSocketErrorCode = !UnsafeNativeMethods.WebSocketProtocolComponent.Succeeded(nativeError) ? WebSocketError.NativeError : WebSocketError.Success; - this.SetErrorCodeOnError(nativeError); - } - - public WebSocketException(int nativeError, string message) - : base(nativeError, message) - { - _WebSocketErrorCode = !UnsafeNativeMethods.WebSocketProtocolComponent.Succeeded(nativeError) ? WebSocketError.NativeError : WebSocketError.Success; - this.SetErrorCodeOnError(nativeError); - } - - public WebSocketException(int nativeError, Exception innerException) - : base(SR.GetString(SR.net_WebSockets_Generic), innerException) - { - _WebSocketErrorCode = !UnsafeNativeMethods.WebSocketProtocolComponent.Succeeded(nativeError) ? WebSocketError.NativeError : WebSocketError.Success; - this.SetErrorCodeOnError(nativeError); - } - - public WebSocketException(WebSocketError error, int nativeError) - : this(error, nativeError, GetErrorMessage(error)) - { - } - - public WebSocketException(WebSocketError error, int nativeError, string message) - : base(message) - { - _WebSocketErrorCode = error; - this.SetErrorCodeOnError(nativeError); - } - - public WebSocketException(WebSocketError error, int nativeError, Exception innerException) - : this(error, nativeError, GetErrorMessage(error), innerException) - { - } - - public WebSocketException(WebSocketError error, int nativeError, string message, Exception innerException) - : base(message, innerException) - { - _WebSocketErrorCode = error; - this.SetErrorCodeOnError(nativeError); - } - - public WebSocketException(string message) - : base(message) - { - } - - public WebSocketException(string message, Exception innerException) - : base(message, innerException) - { - } -#if !NETSTANDARD1_3 - public override int ErrorCode - { - get - { - return base.NativeErrorCode; - } - } -#endif - public WebSocketError WebSocketErrorCode - { - get - { - return _WebSocketErrorCode; - } - } - - private static string GetErrorMessage(WebSocketError error) - { - // provide a canned message for the error type - switch (error) - { - case WebSocketError.InvalidMessageType: - return SR.GetString(SR.net_WebSockets_InvalidMessageType_Generic, - typeof(WebSocket).Name + WebSocketBase.Methods.CloseAsync, - typeof(WebSocket).Name + WebSocketBase.Methods.CloseOutputAsync); - case WebSocketError.Faulted: - return SR.GetString(SR.net_Websockets_WebSocketBaseFaulted); - case WebSocketError.NotAWebSocket: - return SR.GetString(SR.net_WebSockets_NotAWebSocket_Generic); - case WebSocketError.UnsupportedVersion: - return SR.GetString(SR.net_WebSockets_UnsupportedWebSocketVersion_Generic); - case WebSocketError.UnsupportedProtocol: - return SR.GetString(SR.net_WebSockets_UnsupportedProtocol_Generic); - case WebSocketError.HeaderError: - return SR.GetString(SR.net_WebSockets_HeaderError_Generic); - case WebSocketError.ConnectionClosedPrematurely: - return SR.GetString(SR.net_WebSockets_ConnectionClosedPrematurely_Generic); - case WebSocketError.InvalidState: - return SR.GetString(SR.net_WebSockets_InvalidState_Generic); - default: - return SR.GetString(SR.net_WebSockets_Generic); - } - } - - // Set the error code only if there is an error (i.e. nativeError >= 0). Otherwise the code blows up on deserialization - // as the Exception..ctor() throws on setting HResult to 0. The default for HResult is -2147467259. - private void SetErrorCodeOnError(int nativeError) - { - if (!UnsafeNativeMethods.WebSocketProtocolComponent.Succeeded(nativeError)) - { - this.HResult = nativeError; - } - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketExtensions.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketExtensions.cs deleted file mode 100644 index dccc933241..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketExtensions.cs +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.IO; -using System.Net.WebSockets; -using System.Threading.Tasks; -using Microsoft.Net.WebSockets; - -namespace Microsoft.Net.Http.Server -{ - public static class WebSocketExtensions - { - public static bool IsWebSocketRequest(this RequestContext context) - { - if (!WebSocketHelpers.AreWebSocketsSupported) - { - return false; - } - - if (!context.IsUpgradableRequest) - { - return false; - } - - if (!string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - string connection = context.Request.Headers[HttpKnownHeaderNames.Connection]; - if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) - { - return false; - } - - // Upgrade: websocket - string upgrade = context.Request.Headers[HttpKnownHeaderNames.Upgrade]; - if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Sec-WebSocket-Version: 13 - string version = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Sec-WebSocket-Key: {base64string} - string key = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - if (!WebSocketHelpers.IsValidWebSocketKey(key)) - { - return false; - } - - return true; - } - - // Compare IsWebSocketRequest() - private static void ValidateWebSocketRequest(RequestContext context) - { - if (!WebSocketHelpers.AreWebSocketsSupported) - { - throw new NotSupportedException("WebSockets are not supported on this platform."); - } - - if (!context.IsUpgradableRequest) - { - throw new InvalidOperationException("This request is not a valid upgrade request."); - } - - if (!string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("This request is not a valid upgrade request; invalid verb: " + context.Request.Method); - } - - // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - string connection = context.Request.Headers[HttpKnownHeaderNames.Connection]; - if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) - { - throw new InvalidOperationException("The Connection header is invalid: " + connection); - } - - // Upgrade: websocket - string upgrade = context.Request.Headers[HttpKnownHeaderNames.Upgrade]; - if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("The Upgrade header is invalid: " + upgrade); - } - - // Sec-WebSocket-Version: 13 - string version = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - if (!string.Equals(WebSocketConstants.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("The Sec-WebSocket-Version header is invalid or not supported: " + version); - } - - // Sec-WebSocket-Key: {base64string} - string key = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - if (!WebSocketHelpers.IsValidWebSocketKey(key)) - { - throw new InvalidOperationException("The Sec-WebSocket-Key header is invalid: " + upgrade); - } - } - - public static Task AcceptWebSocketAsync(this RequestContext context) - { - return context.AcceptWebSocketAsync(null, - WebSocketHelpers.DefaultReceiveBufferSize, - WebSocketHelpers.DefaultKeepAliveInterval); - } - - public static Task AcceptWebSocketAsync(this RequestContext context, string subProtocol) - { - return context.AcceptWebSocketAsync(subProtocol, - WebSocketHelpers.DefaultReceiveBufferSize, - WebSocketHelpers.DefaultKeepAliveInterval); - } - - public static Task AcceptWebSocketAsync(this RequestContext context, string subProtocol, TimeSpan keepAliveInterval) - { - return context.AcceptWebSocketAsync(subProtocol, - WebSocketHelpers.DefaultReceiveBufferSize, - keepAliveInterval); - } - - public static Task AcceptWebSocketAsync( - this RequestContext context, - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval) - { - WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); - - ArraySegment internalBuffer = WebSocketBuffer.CreateInternalBufferArraySegment(receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - return context.AcceptWebSocketAsync(subProtocol, - receiveBufferSize, - keepAliveInterval, - internalBuffer); - } - - public static Task AcceptWebSocketAsync( - this RequestContext context, - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) - { - if (!context.IsUpgradableRequest) - { - throw new InvalidOperationException("This request is cannot be upgraded."); - } - WebSocketHelpers.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval); - WebSocketHelpers.ValidateArraySegment(internalBuffer, "internalBuffer"); - WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true); - - return AcceptWebSocketAsyncCore(context, subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer); - } - - private static async Task AcceptWebSocketAsyncCore( - RequestContext context, - string subProtocol, - int receiveBufferSize, - TimeSpan keepAliveInterval, - ArraySegment internalBuffer) - { - ValidateWebSocketRequest(context); - - var subProtocols = context.Request.Headers.GetValues(HttpKnownHeaderNames.SecWebSocketProtocol); - bool shouldSendSecWebSocketProtocolHeader = WebSocketHelpers.ProcessWebSocketProtocolHeader(subProtocols, subProtocol); - if (shouldSendSecWebSocketProtocolHeader) - { - context.Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = subProtocol; - } - - // negotiate the websocket key return value - string secWebSocketKey = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - string secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); - - context.Response.Headers.Append(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); - context.Response.Headers.Append(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); - context.Response.Headers.Append(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); - - Stream opaqueStream = await context.UpgradeAsync(); - - return WebSocketHelpers.CreateServerWebSocket( - opaqueStream, - subProtocol, - receiveBufferSize, - keepAliveInterval, - internalBuffer); - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketHelpers.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketHelpers.cs deleted file mode 100644 index 21e0b11838..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketHelpers.cs +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net.WebSockets; -using System.Runtime.CompilerServices; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Net.WebSockets -{ - public static class WebSocketHelpers - { - internal const string SecWebSocketKeyGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - public const string WebSocketUpgradeToken = "websocket"; - public const int DefaultReceiveBufferSize = 16 * 1024; - internal const int DefaultClientSendBufferSize = 16 * 1024; - internal const int MaxControlFramePayloadLength = 123; - - // RFC 6455 requests WebSocket clients to let the server initiate the TCP close to avoid that client sockets - // end up in TIME_WAIT-state - // - // After both sending and receiving a Close message, an endpoint considers the WebSocket connection closed and - // MUST close the underlying TCP connection. The server MUST close the underlying TCP connection immediately; - // the client SHOULD wait for the server to close the connection but MAY close the connection at any time after - // sending and receiving a Close message, e.g., if it has not received a TCP Close from the server in a - // reasonable time period. - internal const int ClientTcpCloseTimeout = 1000; // 1s - - private const int CloseStatusCodeAbort = 1006; - private const int CloseStatusCodeFailedTLSHandshake = 1015; - private const int InvalidCloseStatusCodesFrom = 0; - private const int InvalidCloseStatusCodesTo = 999; - private const string Separators = "()<>@,;:\\\"/[]?={} "; - - internal static readonly ArraySegment EmptyPayload = new ArraySegment(new byte[] { }, 0, 0); - private static readonly Random KeyGenerator = new Random(); - private static TimeSpan? _defaultKeepAliveInterval; - - public static bool AreWebSocketsSupported - { - get - { - return UnsafeNativeMethods.WebSocketProtocolComponent.IsSupported; - } - } - - public static TimeSpan DefaultKeepAliveInterval - { - get - { - if (!_defaultKeepAliveInterval.HasValue) - { - if (AreWebSocketsSupported) - { - _defaultKeepAliveInterval = new TimeSpan?(UnsafeNativeMethods.WebSocketProtocolComponent.WebSocketGetDefaultKeepAliveInterval()); - } - else - { - _defaultKeepAliveInterval = new TimeSpan?(Timeout.InfiniteTimeSpan); - } - } - return _defaultKeepAliveInterval.Value; - } - } - - public static bool IsValidWebSocketKey(string key) - { - if (string.IsNullOrWhiteSpace(key)) - { - return false; - } - // TODO: - // throw new NotImplementedException(); - return true; - } - - [SuppressMessage("Microsoft.Cryptographic.Standard", "CA5354:SHA1CannotBeUsed", - Justification = "SHA1 used only for hashing purposes, not for crypto.")] - public static string GetSecWebSocketAcceptString(string secWebSocketKey) - { - string retVal; - // SHA1 used only for hashing purposes, not for crypto. Check here for FIPS compat. - using (SHA1 sha1 = SHA1.Create()) - { - string acceptString = string.Concat(secWebSocketKey, WebSocketHelpers.SecWebSocketKeyGuid); - byte[] toHash = Encoding.UTF8.GetBytes(acceptString); - retVal = Convert.ToBase64String(sha1.ComputeHash(toHash)); - } - return retVal; - } - - public static WebSocket CreateServerWebSocket(Stream opaqueStream, string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval, ArraySegment internalBuffer) - { - return new ServerWebSocket(opaqueStream, subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer); - } - - internal static string GetTraceMsgForParameters(int offset, int count, CancellationToken cancellationToken) - { - return string.Format(CultureInfo.InvariantCulture, - "offset: {0}, count: {1}, cancellationToken.CanBeCanceled: {2}", - offset, - count, - cancellationToken.CanBeCanceled); - } - - // return value here signifies if a Sec-WebSocket-Protocol header should be returned by the server. - public static bool ProcessWebSocketProtocolHeader(IEnumerable clientSecWebSocketProtocols, string subProtocol) - { - if (clientSecWebSocketProtocols == null || !clientSecWebSocketProtocols.Any()) - { - // client hasn't specified any Sec-WebSocket-Protocol header - if (subProtocol != null) - { - // If the server specified _anything_ this isn't valid. - throw new WebSocketException(WebSocketError.UnsupportedProtocol, - SR.GetString(SR.net_WebSockets_ClientAcceptingNoProtocols, subProtocol)); - } - // Treat empty and null from the server as the same thing here, server should not send headers. - return false; - } - - // here, we know the client specified something and it's non-empty. - - if (string.IsNullOrEmpty(subProtocol)) - { - // client specified some protocols, server specified 'null'. So server should send headers. - return false; - } - - // here, we know that the client has specified something, it's not empty - // and the server has specified exactly one protocol - - // client specified protocols, serverOptions has exactly 1 non-empty entry. Check that - // this exists in the list the client specified. - foreach (var currentRequestProtocol in clientSecWebSocketProtocols) - { - if (string.Compare(subProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase) == 0) - { - return true; - } - } - - throw new WebSocketException(WebSocketError.UnsupportedProtocol, - SR.GetString(SR.net_WebSockets_AcceptUnsupportedProtocol, - string.Join(", ", clientSecWebSocketProtocols), - subProtocol)); - } - - internal static ConfiguredTaskAwaitable SuppressContextFlow(this Task task) - { - // We don't flow the synchronization context within WebSocket.xxxAsync - but the calling application - // can decide whether the completion callback for the task returned from WebSocket.xxxAsync runs - // under the caller's synchronization context. - return task.ConfigureAwait(false); - } - - internal static ConfiguredTaskAwaitable SuppressContextFlow(this Task task) - { - // We don't flow the synchronization context within WebSocket.xxxAsync - but the calling application - // can decide whether the completion callback for the task returned from WebSocket.xxxAsync runs - // under the caller's synchronization context. - return task.ConfigureAwait(false); - } - - internal static bool IsStateTerminal(WebSocketState state) - { - return state == WebSocketState.Closed || state == WebSocketState.Aborted; - } - - internal static void ThrowOnInvalidState(WebSocketState state, params WebSocketState[] validStates) - { - string text = string.Empty; - if (validStates != null && validStates.Length > 0) - { - for (int i = 0; i < validStates.Length; i++) - { - WebSocketState webSocketState = validStates[i]; - if (state == webSocketState) - { - return; - } - } - text = string.Join(", ", validStates); - } - throw new WebSocketException(SR.GetString("net_WebSockets_InvalidState", new object[] - { - state, - text - })); - } - - internal static void ValidateBuffer(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - if (offset < 0 || offset > buffer.Length) - { - throw new ArgumentOutOfRangeException("offset"); - } - - if (count < 0 || count > (buffer.Length - offset)) - { - throw new ArgumentOutOfRangeException("count"); - } - } - - internal static void ValidateSubprotocol(string subProtocol) - { - if (string.IsNullOrWhiteSpace(subProtocol)) - { - throw new ArgumentException(SR.GetString(SR.net_WebSockets_InvalidEmptySubProtocol), "subProtocol"); - } - - char[] chars = subProtocol.ToCharArray(); - string invalidChar = null; - int i = 0; - while (i < chars.Length) - { - char ch = chars[i]; - if (ch < 0x21 || ch > 0x7e) - { - invalidChar = string.Format(CultureInfo.InvariantCulture, "[{0}]", (int)ch); - break; - } - - if (!char.IsLetterOrDigit(ch) && - Separators.IndexOf(ch) >= 0) - { - invalidChar = ch.ToString(); - break; - } - - i++; - } - - if (invalidChar != null) - { - throw new ArgumentException(SR.GetString(SR.net_WebSockets_InvalidCharInProtocolString, subProtocol, invalidChar), - "subProtocol"); - } - } - - internal static void ValidateCloseStatus(WebSocketCloseStatus closeStatus, string statusDescription) - { - if (closeStatus == WebSocketCloseStatus.Empty && !string.IsNullOrEmpty(statusDescription)) - { - throw new ArgumentException(SR.GetString(SR.net_WebSockets_ReasonNotNull, - statusDescription, - WebSocketCloseStatus.Empty), - "statusDescription"); - } - - int closeStatusCode = (int)closeStatus; - - if ((closeStatusCode >= InvalidCloseStatusCodesFrom && - closeStatusCode <= InvalidCloseStatusCodesTo) || - closeStatusCode == CloseStatusCodeAbort || - closeStatusCode == CloseStatusCodeFailedTLSHandshake) - { - // CloseStatus 1006 means Aborted - this will never appear on the wire and is reflected by calling WebSocket.Abort - throw new ArgumentException(SR.GetString(SR.net_WebSockets_InvalidCloseStatusCode, - closeStatusCode), - "closeStatus"); - } - - int length = 0; - if (!string.IsNullOrEmpty(statusDescription)) - { - length = UTF8Encoding.UTF8.GetByteCount(statusDescription); - } - - if (length > WebSocketHelpers.MaxControlFramePayloadLength) - { - throw new ArgumentException(SR.GetString(SR.net_WebSockets_InvalidCloseStatusDescription, - statusDescription, - WebSocketHelpers.MaxControlFramePayloadLength), - "statusDescription"); - } - } - - public static void ValidateOptions(string subProtocol, - int receiveBufferSize, - int sendBufferSize, - TimeSpan keepAliveInterval) - { - // We allow the subProtocol to be null. Validate if it is not null. - if (subProtocol != null) - { - ValidateSubprotocol(subProtocol); - } - - ValidateBufferSizes(receiveBufferSize, sendBufferSize); - - // -1 - if (keepAliveInterval < Timeout.InfiniteTimeSpan) - { - throw new ArgumentOutOfRangeException("keepAliveInterval", keepAliveInterval, - SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, Timeout.InfiniteTimeSpan.ToString())); - } - } - - internal static void ValidateBufferSizes(int receiveBufferSize, int sendBufferSize) - { - if (receiveBufferSize < WebSocketBuffer.MinReceiveBufferSize) - { - throw new ArgumentOutOfRangeException("receiveBufferSize", receiveBufferSize, - SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, WebSocketBuffer.MinReceiveBufferSize)); - } - - if (sendBufferSize < WebSocketBuffer.MinSendBufferSize) - { - throw new ArgumentOutOfRangeException("sendBufferSize", sendBufferSize, - SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, WebSocketBuffer.MinSendBufferSize)); - } - - if (receiveBufferSize > WebSocketBuffer.MaxBufferSize) - { - throw new ArgumentOutOfRangeException("receiveBufferSize", receiveBufferSize, - SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooBig, - "receiveBufferSize", - receiveBufferSize, - WebSocketBuffer.MaxBufferSize)); - } - - if (sendBufferSize > WebSocketBuffer.MaxBufferSize) - { - throw new ArgumentOutOfRangeException("sendBufferSize", sendBufferSize, - SR.GetString(SR.net_WebSockets_ArgumentOutOfRange_TooBig, - "sendBufferSize", - sendBufferSize, - WebSocketBuffer.MaxBufferSize)); - } - } - - internal static void ValidateInnerStream(Stream innerStream) - { - if (innerStream == null) - { - throw new ArgumentNullException("innerStream"); - } - - if (!innerStream.CanRead) - { - throw new ArgumentException(SR.GetString(SR.NotReadableStream), "innerStream"); - } - - if (!innerStream.CanWrite) - { - throw new ArgumentException(SR.GetString(SR.NotWriteableStream), "innerStream"); - } - } - - internal static void ThrowIfConnectionAborted(Stream connection, bool read) - { - if ((!read && !connection.CanWrite) || - (read && !connection.CanRead)) - { - throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely); - } - } - - internal static void ThrowPlatformNotSupportedException_WSPC() - { - throw new PlatformNotSupportedException(SR.GetString(SR.net_WebSockets_UnsupportedPlatform)); - } - - public static void ValidateArraySegment(ArraySegment arraySegment, string parameterName) - { - Contract.Requires(!string.IsNullOrEmpty(parameterName), "'parameterName' MUST NOT be NULL or string.Empty"); - - if (arraySegment.Array == null) - { - throw new ArgumentNullException(parameterName + ".Array"); - } - - if (arraySegment.Offset < 0 || arraySegment.Offset > arraySegment.Array.Length) - { - throw new ArgumentOutOfRangeException(parameterName + ".Offset"); - } - if (arraySegment.Count < 0 || arraySegment.Count > (arraySegment.Array.Length - arraySegment.Offset)) - { - throw new ArgumentOutOfRangeException(parameterName + ".Count"); - } - } - } -} diff --git a/src/Microsoft.Net.WebSockets.Server/WebSocketReceiveResultExtensions.cs b/src/Microsoft.Net.WebSockets.Server/WebSocketReceiveResultExtensions.cs deleted file mode 100644 index 12841af2df..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/WebSocketReceiveResultExtensions.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -using System; -using System.Diagnostics.Contracts; -using System.Net.WebSockets; - -namespace Microsoft.Net.WebSockets -{ - internal static class WebSocketReceiveResultExtensions - { - internal static WebSocketReceiveResult DecrementAndClone(ref WebSocketReceiveResult original, int count) - { - Contract.Assert(count >= 0, "'count' MUST NOT be negative."); - Contract.Assert(count <= original.Count, "'count' MUST NOT be bigger than 'this.Count'."); - int remaining = original.Count - count; - original = new WebSocketReceiveResult(remaining, - original.MessageType, - original.EndOfMessage, - original.CloseStatus, - original.CloseStatusDescription); - return new WebSocketReceiveResult(count, - original.MessageType, - remaining == 0 && original.EndOfMessage, - original.CloseStatus, - original.CloseStatusDescription); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs deleted file mode 100644 index aef2c8b323..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ==++== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ==--== - -#if NETSTANDARD1_3 - -namespace Microsoft.Win32.SafeHandles -{ - using System; - using System.Runtime.InteropServices; - using System.Runtime.CompilerServices; - - // Class of safe handle which uses 0 or -1 as an invalid handle. - [System.Security.SecurityCritical] // auto-generated_required - internal abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle - { - protected SafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) - : base(IntPtr.Zero, ownsHandle) - { - } - - public override bool IsInvalid - { - [System.Security.SecurityCritical] - get { return handle == new IntPtr(0) || handle == new IntPtr(-1); } - } - } -} -#endif diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs deleted file mode 100644 index 0345bbc1a1..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/AccessViolationException.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -#if NETSTANDARD1_3 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System -{ - internal class AccessViolationException : SystemException - { - } -} - -#endif diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs deleted file mode 100644 index 989211c70c..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/ExternDll.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -#if NETSTANDARD1_3 - -namespace System -{ - internal static class ExternDll - { - public const string api_ms_win_core_localization_LIB = "api-ms-win-core-localization-l2-1-0.dll"; - } -} -#endif diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs deleted file mode 100644 index 807bdd2a60..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ==++== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ==--== -/*============================================================================= -** -** Class: ExternalException -** -** -** Purpose: Exception base class for all errors from Interop or Structured -** Exception Handling code. -** -** -=============================================================================*/ - -#if NETSTANDARD1_3 - -namespace System.Runtime.InteropServices -{ - using System; - using System.Globalization; - - // Base exception for COM Interop errors &; Structured Exception Handler - // exceptions. - // - internal class ExternalException : Exception - { - public ExternalException() - { - SetErrorCode(__HResults.E_FAIL); - } - - public ExternalException(String message) - : base(message) - { - SetErrorCode(__HResults.E_FAIL); - } - - public ExternalException(String message, Exception inner) - : base(message, inner) - { - SetErrorCode(__HResults.E_FAIL); - } - - public ExternalException(String message, int errorCode) - : base(message) - { - SetErrorCode(errorCode); - } - - private void SetErrorCode(int errorCode) - { - HResult = ErrorCode; - } - - private static class __HResults - { - internal const int E_FAIL = unchecked((int)0x80004005); - } - - public virtual int ErrorCode - { - get - { - return HResult; - } - } - - public override String ToString() - { - String message = Message; - String s; - String _className = GetType().ToString(); - s = _className + " (0x" + HResult.ToString("X8", CultureInfo.InvariantCulture) + ")"; - - if (!(String.IsNullOrEmpty(message))) - { - s = s + ": " + message; - } - - Exception _innerException = InnerException; - - if (_innerException != null) - { - s = s + " ---> " + _innerException.ToString(); - } - - - if (StackTrace != null) - s += Environment.NewLine + StackTrace; - - return s; - } - } -} - -#endif diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs deleted file mode 100644 index 27a17a745c..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/SafeNativeMethods.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -#if NETSTANDARD1_3 -using System.Runtime.InteropServices; -using System.Text; - -namespace System -{ - internal static class SafeNativeMethods - { - public const int - FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, - FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, - FORMAT_MESSAGE_FROM_STRING = 0x00000400, - FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, - FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; - - [DllImport(ExternDll.api_ms_win_core_localization_LIB, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] - public static unsafe extern int FormatMessage(int dwFlags, IntPtr lpSource_mustBeNull, uint dwMessageId, - int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr[] arguments); - } -} -#endif diff --git a/src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs b/src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs deleted file mode 100644 index 3b4436eb4e..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/fx/System/SystemException.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -#if NETSTANDARD1_3 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace System -{ - internal class SystemException : Exception - { - } -} - -#endif diff --git a/src/Microsoft.Net.WebSockets.Server/project.json b/src/Microsoft.Net.WebSockets.Server/project.json deleted file mode 100644 index dda1bf4231..0000000000 --- a/src/Microsoft.Net.WebSockets.Server/project.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": "0.2.0-*", - "description": "Implementation of WebSocket abstract base class. Used by WebListener.", - "dependencies": { - "Microsoft.Net.Http.Server": "0.2.0-*" - }, - "buildOptions": { - "allowUnsafe": true, - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "frameworks": { - "net451": {}, - "netstandard1.3": { - "dependencies": { - "System.Collections": "4.0.11-*", - "System.Linq": "4.1.0-*", - "System.Net.WebSockets": "4.0.0-*", - "System.Resources.ResourceManager": "4.0.1-*", - "System.Runtime.Extensions": "4.1.0-*", - "System.Security.Cryptography.Algorithms": "4.2.0-*", - "System.Threading": "4.0.11-*", - "System.Threading.Tasks": "4.0.11-*", - "System.Threading.Timer": "4.0.1-*", - "System.Threading.ThreadPool": "4.0.10-*" - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs index c34936f454..896dc42a57 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -14,7 +14,7 @@ // NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing // permissions and limitations under the License. -#if WEBSOCKETS + using System; using System.Net.Http; using System.Net.WebSockets; @@ -159,10 +159,9 @@ namespace Microsoft.AspNetCore.Server.WebListener private async Task SendWebSocketRequestAsync(string address) { - ClientWebSocket client = new ClientWebSocket(); + var client = new ClientWebSocket(); await client.ConnectAsync(new Uri(address), CancellationToken.None); return client; } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index c79eb2c3f8..d25973f484 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -19,7 +19,8 @@ }, "System.Net.Http.WinHttpHandler": "4.0.0-*", "System.Net.Requests": "4.0.11-*", - "System.Net.WebHeaderCollection": "4.0.1-*" + "System.Net.WebHeaderCollection": "4.0.1-*", + "System.Net.WebSockets.Client": "4.0.0" } }, "net451": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index 96bbedaea8..7fb09686ee 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -62,7 +62,7 @@ namespace Microsoft.Net.Http.Server Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); var context = await server.AcceptAsync(); - Assert.True(context.IsWebSocketRequest()); + Assert.True(context.IsWebSocketRequest); WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); WebSocket clientWebSocket = await clientTask; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index d823390cbc..399d8dc19d 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -3,7 +3,6 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.Net.Http.Server": "0.2.0-*", - "Microsoft.Net.WebSockets.Server": "0.2.0-*", "Microsoft.AspNetCore.Testing": "1.1.0-*", "xunit": "2.2.0-*" }, From a9b5cec33dad71f129a260422934b2747d2103d8 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 3 Aug 2016 10:57:20 -0700 Subject: [PATCH 367/597] Remove old WebSockets.Server package from NuGetPackageVerifier --- NuGetPackageVerifier.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index d13c12ca63..7ae83febd7 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -5,8 +5,7 @@ ], "packages": { "Microsoft.AspNetCore.Server.WebListener": { }, - "Microsoft.Net.Http.Server": { }, - "Microsoft.Net.WebSockets.Server": { } + "Microsoft.Net.Http.Server": { } } }, "Default": { // Ru les to run for packages not listed in any other set. From 4b36501bd84ca0ab1713da272f95b1c6f33ef5f2 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 5 Aug 2016 16:18:30 -0700 Subject: [PATCH 368/597] #160 Move AllowAnonymous from the AuthenticationSchemes to its own bool --- samples/SelfHostServer/Startup.cs | 6 ++- .../AuthenticationManager.cs | 21 +++----- .../AuthenticationSchemes.cs | 3 +- .../RequestProcessing/Response.cs | 2 +- .../AuthenticationTests.cs | 49 ++++++++++--------- .../Utilities.cs | 11 +++-- .../AuthenticationTests.cs | 30 +++++------- .../Utilities.cs | 3 +- 8 files changed, 59 insertions(+), 66 deletions(-) diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 81875a0af2..e85fff80f9 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -19,7 +19,8 @@ namespace SelfHostServer // Server options can be configured here instead of in Main. services.Configure(options => { - options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; + options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.None; + options.Listener.AuthenticationManager.AllowAnonymous = true; }); } @@ -51,7 +52,8 @@ namespace SelfHostServer .UseStartup() .UseWebListener(options => { - options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.AllowAnonymous; + options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.None; + options.Listener.AuthenticationManager.AllowAnonymous = true; }) .Build(); diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 32d7ee2e69..cad91f8c30 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -44,38 +44,29 @@ namespace Microsoft.Net.Http.Server private WebListener _server; private AuthenticationSchemes _authSchemes; + private bool _allowAnonymous = true; internal AuthenticationManager(WebListener listener) { _server = listener; - _authSchemes = AuthenticationSchemes.AllowAnonymous; } #region Properties public AuthenticationSchemes AuthenticationSchemes { - get - { - return _authSchemes; - } + get { return _authSchemes; } set { - if (_authSchemes == AuthenticationSchemes.None) - { - throw new ArgumentException("value", "'None' is not a valid authentication type. Use 'AllowAnonymous' instead."); - } _authSchemes = value; SetServerSecurity(); } } - internal bool AllowAnonymous + public bool AllowAnonymous { - get - { - return ((_authSchemes & AuthenticationSchemes.AllowAnonymous) == AuthenticationSchemes.AllowAnonymous); - } + get { return _allowAnonymous; } + set { _allowAnonymous = value; } } #endregion Properties @@ -86,7 +77,7 @@ namespace Microsoft.Net.Http.Server new UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO(); authInfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; - var authSchemes = (UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES)(_authSchemes & ~AuthenticationSchemes.AllowAnonymous); + var authSchemes = (UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES)_authSchemes; if (authSchemes != UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES.NONE) { authInfo.AuthSchemes = authSchemes; diff --git a/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs b/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs index d8ee617c16..1f53175cbd 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs @@ -28,7 +28,6 @@ namespace Microsoft.Net.Http.Server // Digest = 0x2, // TODO: Verify this is no longer supported by Http.Sys NTLM = 0x4, Negotiate = 0x8, - Kerberos = 0x10, - AllowAnonymous = 0x1000 + Kerberos = 0x10 } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 12d7a51bae..1203105e3f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -82,7 +82,7 @@ namespace Microsoft.Net.Http.Server _expectedBodyLength = 0; _nativeStream = null; _cacheTtl = null; - _authChallenges = RequestContext.Server.AuthenticationManager.AuthenticationSchemes & ~AuthenticationSchemes.AllowAnonymous; + _authChallenges = RequestContext.Server.AuthenticationManager.AuthenticationSchemes; } private enum ResponseState diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 7606cc1bc9..e96eb7040f 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -29,8 +29,11 @@ namespace Microsoft.AspNetCore.Server.WebListener { public class AuthenticationTests { + private static bool AllowAnoymous = true; + private static bool DenyAnoymous = false; + [Theory] - [InlineData(AuthenticationSchemes.AllowAnonymous)] + [InlineData(AuthenticationSchemes.None)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -39,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -62,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => { throw new NotImplementedException(); })) @@ -82,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -106,8 +109,8 @@ namespace Microsoft.AspNetCore.Server.WebListener AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM /* | AuthenticationSchemes.Digest TODO: Not implemented */ - | AuthenticationSchemes.Basic - | AuthenticationSchemes.AllowAnonymous, + | AuthenticationSchemes.Basic, + true, out address, httpContext => { @@ -134,7 +137,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { string address; int requestId = 0; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -169,7 +172,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -183,7 +186,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } [Theory] - [InlineData(AuthenticationSchemes.AllowAnonymous)] + [InlineData(AuthenticationSchemes.None)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -191,10 +194,10 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthTypes_GetSingleDescriptions(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => { var resultList = httpContext.Authentication.GetAuthenticationSchemes(); - if (authType == AuthenticationSchemes.AllowAnonymous) + if (authType == AuthenticationSchemes.None) { Assert.Equal(0, resultList.Count()); } @@ -224,7 +227,7 @@ namespace Microsoft.AspNetCore.Server.WebListener | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => { var resultList = httpContext.Authentication.GetAuthenticationSchemes(); Assert.Equal(3, resultList.Count()); @@ -247,7 +250,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, async httpContext => + using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, async httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -275,7 +278,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType, out address, async httpContext => + using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, async httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -308,7 +311,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -333,7 +336,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address, async httpContext => + using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, async httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -360,7 +363,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { string address; var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -386,7 +389,7 @@ namespace Microsoft.AspNetCore.Server.WebListener var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; authTypes = authTypes & ~authType; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authTypes | AuthenticationSchemes.AllowAnonymous, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -408,8 +411,8 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthTypes_Forbid_Forbidden(AuthenticationSchemes authType) { string address; - var authTypes = AuthenticationSchemes.AllowAnonymous | AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authTypes, out address, httpContext => + var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; + using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -431,7 +434,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthTypes_ChallengeAuthenticatedAuthType_Forbidden(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -454,7 +457,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -477,7 +480,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public async Task AuthTypes_UnathorizedAuthenticatedAuthType_Unauthorized(AuthenticationSchemes authType) { string address; - using (Utilities.CreateHttpAuthServer(authType, out address, httpContext => + using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs index b78a3d8b15..35dbaa848b 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs @@ -38,22 +38,22 @@ namespace Microsoft.AspNetCore.Server.WebListener internal static IServer CreateHttpServer(out string baseAddress, RequestDelegate app) { string root; - return CreateDynamicHttpServer(string.Empty, AuthenticationSchemes.AllowAnonymous, out root, out baseAddress, app); + return CreateDynamicHttpServer(string.Empty, AuthenticationSchemes.None, true, out root, out baseAddress, app); } internal static IServer CreateHttpServerReturnRoot(string path, out string root, RequestDelegate app) { string baseAddress; - return CreateDynamicHttpServer(path, AuthenticationSchemes.AllowAnonymous, out root, out baseAddress, app); + return CreateDynamicHttpServer(path, AuthenticationSchemes.None, true, out root, out baseAddress, app); } - internal static IServer CreateHttpAuthServer(AuthenticationSchemes authType, out string baseAddress, RequestDelegate app) + internal static IServer CreateHttpAuthServer(AuthenticationSchemes authType, bool allowAnonymous, out string baseAddress, RequestDelegate app) { string root; - return CreateDynamicHttpServer(string.Empty, authType, out root, out baseAddress, app); + return CreateDynamicHttpServer(string.Empty, authType, allowAnonymous, out root, out baseAddress, app); } - internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, out string root, out string baseAddress, RequestDelegate app) + internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, bool allowAnonymous, out string root, out string baseAddress, RequestDelegate app) { lock (PortLock) { @@ -68,6 +68,7 @@ namespace Microsoft.AspNetCore.Server.WebListener var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); server.Features.Get().Addresses.Add(baseAddress); server.Listener.AuthenticationManager.AuthenticationSchemes = authType; + server.Listener.AuthenticationManager.AllowAnonymous = allowAnonymous; try { server.Start(new DummyApplication(app)); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 3ad4c842ae..8009331223 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -11,8 +11,11 @@ namespace Microsoft.Net.Http.Server { public class AuthenticationTests { + private static bool AllowAnoymous = true; + private static bool DenyAnoymous = false; + [Theory] - [InlineData(AuthenticationSchemes.AllowAnonymous)] + [InlineData(AuthenticationSchemes.None)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -21,21 +24,14 @@ namespace Microsoft.Net.Http.Server public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) { string address; - using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address)) { Task responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); - if (authType == AuthenticationSchemes.AllowAnonymous) - { - Assert.Equal(AuthenticationSchemes.None, context.Response.AuthenticationChallenges); - } - else - { - Assert.Equal(authType, context.Response.AuthenticationChallenges); - } + Assert.Equal(authType, context.Response.AuthenticationChallenges); context.Dispose(); var response = await responseTask; @@ -53,7 +49,7 @@ namespace Microsoft.Net.Http.Server public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; - using (var server = Utilities.CreateHttpAuthServer(authType, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address)) { Task responseTask = SendRequestAsync(address); @@ -73,7 +69,7 @@ namespace Microsoft.Net.Http.Server public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; - using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address)) { Task responseTask = SendRequestAsync(address); @@ -100,7 +96,7 @@ namespace Microsoft.Net.Http.Server | AuthenticationSchemes.NTLM /* | AuthenticationSchemes.Digest TODO: Not implemented */ | AuthenticationSchemes.Basic; - using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address)) { Task responseTask = SendRequestAsync(address); @@ -126,7 +122,7 @@ namespace Microsoft.Net.Http.Server public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType) { string address; - using (var server = Utilities.CreateHttpAuthServer(authType | AuthenticationSchemes.AllowAnonymous, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address)) { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); @@ -157,7 +153,7 @@ namespace Microsoft.Net.Http.Server public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) { string address; - using (var server = Utilities.CreateHttpAuthServer(authType, out address)) + using (var server = Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address)) { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); @@ -177,7 +173,7 @@ namespace Microsoft.Net.Http.Server public async Task AuthTypes_RequireKerberosAuth_Success() { string address; - using (var server = Utilities.CreateHttpAuthServer(AuthenticationSchemes.Kerberos, out address)) + using (var server = Utilities.CreateHttpAuthServer(AuthenticationSchemes.Kerberos, DenyAnoymous, out address)) { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); @@ -197,7 +193,7 @@ namespace Microsoft.Net.Http.Server public async Task MultipleAuthTypes_KerberosAllowAnonymousButSpecify401_ChallengesAdded() { string address; - using (var server = Utilities.CreateHttpAuthServer(AuthenticationSchemes.Kerberos | AuthenticationSchemes.AllowAnonymous, out address)) + using (var server = Utilities.CreateHttpAuthServer(AuthenticationSchemes.Kerberos, AllowAnoymous, out address)) { Task responseTask = SendRequestAsync(address); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs index d9240c02bc..73dc5466b7 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs @@ -14,10 +14,11 @@ namespace Microsoft.Net.Http.Server private static int NextPort = BasePort; private static object PortLock = new object(); - internal static WebListener CreateHttpAuthServer(AuthenticationSchemes authScheme, out string baseAddress) + internal static WebListener CreateHttpAuthServer(AuthenticationSchemes authScheme, bool allowAnonymos, out string baseAddress) { var listener = CreateHttpServer(out baseAddress); listener.AuthenticationManager.AuthenticationSchemes = authScheme; + listener.AuthenticationManager.AllowAnonymous = allowAnonymos; return listener; } From ce06c0b241ee32df51e9d9940cd597567e293421 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 8 Aug 2016 13:18:01 -0700 Subject: [PATCH 369/597] Remove unused code. Reduce class nesting. --- .../AsyncAcceptContext.cs | 4 +- .../AuthenticationManager.cs | 38 +- .../NativeInterop/DisconnectListener.cs | 2 +- .../NativeInterop/HttpApi.cs | 1078 +++++++++++++++++ .../NativeInterop/HttpRequestQueueV2Handle.cs | 2 +- .../NativeInterop/HttpServerSessionHandle.cs | 2 +- .../NativeInterop/RequestQueue.cs | 22 +- .../NativeInterop/ServerSession.cs | 4 +- .../NativeInterop/TokenBindingUtil.cs | 2 +- .../NativeInterop/UnsafeNativeMethods.cs | 1067 ---------------- .../NativeInterop/UrlGroup.cs | 12 +- .../RequestProcessing/ClientCertLoader.cs | 30 +- .../RequestProcessing/NativeRequestContext.cs | 14 +- .../RequestProcessing/Request.cs | 20 +- .../RequestProcessing/RequestContext.cs | 6 +- .../RequestProcessing/RequestHeaders.cs | 4 +- .../RequestProcessing/RequestStream.cs | 12 +- .../RequestProcessing/ResponseStream.cs | 6 +- .../TimeoutManager.cs | 42 +- src/Microsoft.Net.Http.Server/WebListener.cs | 38 +- .../fx/System/Diagnostics/TraceEventType.cs | 52 - .../fx/System/ExternDll.cs | 33 - .../InteropServices/ExternalException.cs | 115 -- .../fx/System/SafeNativeMethods.cs | 44 - 24 files changed, 1208 insertions(+), 1441 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs delete mode 100644 src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs delete mode 100644 src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs delete mode 100644 src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs delete mode 100644 src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs diff --git a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs index ba34877b2a..d42a66e605 100644 --- a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs @@ -164,10 +164,10 @@ namespace Microsoft.Net.Http.Server { retry = false; uint bytesTransferred = 0; - statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest( + statusCode = HttpApi.HttpReceiveHttpRequest( Server.RequestQueue.Handle, _nativeRequestContext.RequestBlob->RequestId, - (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, + (uint)HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, _nativeRequestContext.RequestBlob, _nativeRequestContext.Size, &bytesTransferred, diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index cad91f8c30..c1f0ed0ac1 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -40,7 +40,7 @@ namespace Microsoft.Net.Http.Server public sealed class AuthenticationManager { private static readonly int AuthInfoSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private WebListener _server; private AuthenticationSchemes _authSchemes; @@ -73,12 +73,12 @@ namespace Microsoft.Net.Http.Server private unsafe void SetServerSecurity() { - UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO authInfo = - new UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_AUTHENTICATION_INFO(); + HttpApi.HTTP_SERVER_AUTHENTICATION_INFO authInfo = + new HttpApi.HTTP_SERVER_AUTHENTICATION_INFO(); - authInfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; - var authSchemes = (UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES)_authSchemes; - if (authSchemes != UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_TYPES.NONE) + authInfo.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + var authSchemes = (HttpApi.HTTP_AUTH_TYPES)_authSchemes; + if (authSchemes != HttpApi.HTTP_AUTH_TYPES.NONE) { authInfo.AuthSchemes = authSchemes; @@ -92,7 +92,7 @@ namespace Microsoft.Net.Http.Server IntPtr infoptr = new IntPtr(&authInfo); _server.UrlGroup.SetProperty( - UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, + HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, infoptr, (uint)AuthInfoSize); } } @@ -144,25 +144,25 @@ namespace Microsoft.Net.Http.Server } } - internal static unsafe bool CheckAuthenticated(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* requestInfo) + internal static unsafe bool CheckAuthenticated(HttpApi.HTTP_REQUEST_INFO* requestInfo) { if (requestInfo != null - && requestInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth - && requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + && requestInfo->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && requestInfo->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { return true; } return false; } - internal static unsafe ClaimsPrincipal GetUser(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* requestInfo, int infoCount) + internal static unsafe ClaimsPrincipal GetUser(HttpApi.HTTP_REQUEST_INFO* requestInfo, int infoCount) { for (int i = 0; i < infoCount; i++) { var info = &requestInfo[i]; if (requestInfo != null - && info->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth - && info->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + && info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { return new WindowsPrincipal(new WindowsIdentity(info->pInfo->AccessToken, GetAuthTypeFromRequest(info->pInfo->AuthType).ToString())); @@ -171,19 +171,19 @@ namespace Microsoft.Net.Http.Server return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated } - private static AuthenticationSchemes GetAuthTypeFromRequest(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE input) + private static AuthenticationSchemes GetAuthTypeFromRequest(HttpApi.HTTP_REQUEST_AUTH_TYPE input) { switch (input) { - case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic: + case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic: return AuthenticationSchemes.Basic; - // case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest: + // case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest: // return AuthenticationSchemes.Digest; - case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM: + case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM: return AuthenticationSchemes.NTLM; - case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate: + case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate: return AuthenticationSchemes.Negotiate; - case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos: + case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos: return AuthenticationSchemes.Kerberos; default: throw new NotImplementedException(input.ToString()); diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs b/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs index 478a343177..ff45668da9 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs @@ -105,7 +105,7 @@ namespace Microsoft.Net.Http.Server uint statusCode; try { - statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnectEx(requestQueueHandle: _requestQueue.Handle, + statusCode = HttpApi.HttpWaitForDisconnectEx(requestQueueHandle: _requestQueue.Handle, connectionId: connectionId, reserved: 0, overlapped: nativeOverlapped); } catch (Win32Exception exception) diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs new file mode 100644 index 0000000000..74f4de4788 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs @@ -0,0 +1,1078 @@ +// Copyright (c) .NET Foundation. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.Net.Http.Server +{ + internal static unsafe class HttpApi + { + private const string HTTPAPI = "httpapi.dll"; + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpInitialize(HTTPAPI_VERSION version, uint flags, void* pReserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveRequestEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, IntPtr pEntityBuffer, uint entityBufferLength, out uint bytesReturned, SafeNativeOverlapped pOverlapped); + + [DllImport(HTTPAPI, EntryPoint = "HttpReceiveRequestEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveRequestEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, void* pEntityBuffer, uint entityBufferLength, out uint bytesReturned, [In] SafeHandle pOverlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, HTTP_SSL_CLIENT_CERT_INFO* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, byte* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpReceiveHttpRequest(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_REQUEST* pRequestBuffer, uint requestBufferLength, uint* pBytesReturned, SafeNativeOverlapped pOverlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2* pHttpResponse, HTTP_CACHE_POLICY* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK* pEntityChunks, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCancelHttpRequest(SafeHandle requestQueueHandle, ulong requestId, IntPtr pOverlapped); + + [DllImport(HTTPAPI, EntryPoint = "HttpSendResponseEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSendResponseEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, IntPtr pEntityChunks, out uint pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeHandle pOverlapped, IntPtr pLogData); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpWaitForDisconnectEx(SafeHandle requestQueueHandle, ulong connectionId, uint reserved, SafeNativeOverlapped overlapped); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCreateServerSession(HTTPAPI_VERSION version, ulong* serverSessionId, uint reserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCreateUrlGroup(ulong serverSessionId, ulong* urlGroupId, uint reserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint HttpAddUrlToUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, ulong context, uint pReserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSetUrlGroupProperty(ulong urlGroupId, HTTP_SERVER_PROPERTY serverProperty, IntPtr pPropertyInfo, uint propertyInfoLength); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint HttpRemoveUrlFromUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, uint flags); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCloseServerSession(ulong serverSessionId); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpCloseUrlGroup(ulong urlGroupId); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern uint HttpSetRequestQueueProperty(SafeHandle requestQueueHandle, HTTP_SERVER_PROPERTY serverProperty, IntPtr pPropertyInfo, uint propertyInfoLength, uint reserved, IntPtr pReserved); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern unsafe uint HttpCreateRequestQueue(HTTPAPI_VERSION version, string pName, + UnsafeNclNativeMethods.SECURITY_ATTRIBUTES pSecurityAttributes, uint flags, out HttpRequestQueueV2Handle pReqQueueHandle); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); + + internal enum HTTP_API_VERSION + { + Invalid, + Version10, + Version20, + } + + // see http.w for definitions + internal enum HTTP_SERVER_PROPERTY + { + HttpServerAuthenticationProperty, + HttpServerLoggingProperty, + HttpServerQosProperty, + HttpServerTimeoutsProperty, + HttpServerQueueLengthProperty, + HttpServerStateProperty, + HttpServer503VerbosityProperty, + HttpServerBindingProperty, + HttpServerExtendedAuthenticationProperty, + HttpServerListenEndpointProperty, + HttpServerChannelBindProperty, + HttpServerProtectionLevelProperty, + } + + // Currently only one request info type is supported but the enum is for future extensibility. + + internal enum HTTP_REQUEST_INFO_TYPE + { + HttpRequestInfoTypeAuth, + HttpRequestInfoTypeChannelBind, + HttpRequestInfoTypeSslProtocol, + HttpRequestInfoTypeSslTokenBinding + } + + internal enum HTTP_RESPONSE_INFO_TYPE + { + HttpResponseInfoTypeMultipleKnownHeaders, + HttpResponseInfoTypeAuthenticationProperty, + HttpResponseInfoTypeQosProperty, + } + + internal enum HTTP_TIMEOUT_TYPE + { + EntityBody, + DrainEntityBody, + RequestQueue, + IdleConnection, + HeaderWait, + MinSendRate, + } + + internal const int MaxTimeout = 6; + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_VERSION + { + internal ushort MajorVersion; + internal ushort MinorVersion; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_KNOWN_HEADER + { + internal ushort RawValueLength; + internal sbyte* pRawValue; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct HTTP_DATA_CHUNK + { + [FieldOffset(0)] + internal HTTP_DATA_CHUNK_TYPE DataChunkType; + + [FieldOffset(8)] + internal FromMemory fromMemory; + + [FieldOffset(8)] + internal FromFileHandle fromFile; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct FromMemory + { + // 4 bytes for 32bit, 8 bytes for 64bit + internal IntPtr pBuffer; + internal uint BufferLength; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct FromFileHandle + { + internal ulong offset; + internal ulong count; + internal IntPtr fileHandle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTPAPI_VERSION + { + internal ushort HttpApiMajorVersion; + internal ushort HttpApiMinorVersion; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_COOKED_URL + { + internal ushort FullUrlLength; + internal ushort HostLength; + internal ushort AbsPathLength; + internal ushort QueryStringLength; + internal ushort* pFullUrl; + internal ushort* pHost; + internal ushort* pAbsPath; + internal ushort* pQueryString; + } + + // Only cache unauthorized GETs + HEADs. + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_CACHE_POLICY + { + internal HTTP_CACHE_POLICY_TYPE Policy; + internal uint SecondsToLive; + } + + internal enum HTTP_CACHE_POLICY_TYPE : int + { + HttpCachePolicyNocache = 0, + HttpCachePolicyUserInvalidates = 1, + HttpCachePolicyTimeToLive = 2, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SOCKADDR + { + internal ushort sa_family; + internal byte sa_data; + internal byte sa_data_02; + internal byte sa_data_03; + internal byte sa_data_04; + internal byte sa_data_05; + internal byte sa_data_06; + internal byte sa_data_07; + internal byte sa_data_08; + internal byte sa_data_09; + internal byte sa_data_10; + internal byte sa_data_11; + internal byte sa_data_12; + internal byte sa_data_13; + internal byte sa_data_14; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_TRANSPORT_ADDRESS + { + internal SOCKADDR* pRemoteAddress; + internal SOCKADDR* pLocalAddress; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SSL_CLIENT_CERT_INFO + { + internal uint CertFlags; + internal uint CertEncodedSize; + internal byte* pCertEncoded; + internal void* Token; + internal byte CertDeniedByMapper; + } + + internal enum HTTP_SERVICE_BINDING_TYPE : uint + { + HttpServiceBindingTypeNone = 0, + HttpServiceBindingTypeW, + HttpServiceBindingTypeA + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVICE_BINDING_BASE + { + internal HTTP_SERVICE_BINDING_TYPE Type; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_CHANNEL_BIND_STATUS + { + internal IntPtr ServiceName; + internal IntPtr ChannelToken; + internal uint ChannelTokenSize; + internal uint Flags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_UNKNOWN_HEADER + { + internal ushort NameLength; + internal ushort RawValueLength; + internal sbyte* pName; + internal sbyte* pRawValue; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SSL_INFO + { + internal ushort ServerCertKeySize; + internal ushort ConnectionKeySize; + internal uint ServerCertIssuerSize; + internal uint ServerCertSubjectSize; + internal sbyte* pServerCertIssuer; + internal sbyte* pServerCertSubject; + internal HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo; + internal uint SslClientCertNegotiated; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_HEADERS + { + internal ushort UnknownHeaderCount; + internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; + internal ushort TrailerCount; + internal HTTP_UNKNOWN_HEADER* pTrailers; + internal HTTP_KNOWN_HEADER KnownHeaders; + internal HTTP_KNOWN_HEADER KnownHeaders_02; + internal HTTP_KNOWN_HEADER KnownHeaders_03; + internal HTTP_KNOWN_HEADER KnownHeaders_04; + internal HTTP_KNOWN_HEADER KnownHeaders_05; + internal HTTP_KNOWN_HEADER KnownHeaders_06; + internal HTTP_KNOWN_HEADER KnownHeaders_07; + internal HTTP_KNOWN_HEADER KnownHeaders_08; + internal HTTP_KNOWN_HEADER KnownHeaders_09; + internal HTTP_KNOWN_HEADER KnownHeaders_10; + internal HTTP_KNOWN_HEADER KnownHeaders_11; + internal HTTP_KNOWN_HEADER KnownHeaders_12; + internal HTTP_KNOWN_HEADER KnownHeaders_13; + internal HTTP_KNOWN_HEADER KnownHeaders_14; + internal HTTP_KNOWN_HEADER KnownHeaders_15; + internal HTTP_KNOWN_HEADER KnownHeaders_16; + internal HTTP_KNOWN_HEADER KnownHeaders_17; + internal HTTP_KNOWN_HEADER KnownHeaders_18; + internal HTTP_KNOWN_HEADER KnownHeaders_19; + internal HTTP_KNOWN_HEADER KnownHeaders_20; + internal HTTP_KNOWN_HEADER KnownHeaders_21; + internal HTTP_KNOWN_HEADER KnownHeaders_22; + internal HTTP_KNOWN_HEADER KnownHeaders_23; + internal HTTP_KNOWN_HEADER KnownHeaders_24; + internal HTTP_KNOWN_HEADER KnownHeaders_25; + internal HTTP_KNOWN_HEADER KnownHeaders_26; + internal HTTP_KNOWN_HEADER KnownHeaders_27; + internal HTTP_KNOWN_HEADER KnownHeaders_28; + internal HTTP_KNOWN_HEADER KnownHeaders_29; + internal HTTP_KNOWN_HEADER KnownHeaders_30; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_HEADERS + { + internal ushort UnknownHeaderCount; + internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; + internal ushort TrailerCount; + internal HTTP_UNKNOWN_HEADER* pTrailers; + internal HTTP_KNOWN_HEADER KnownHeaders; + internal HTTP_KNOWN_HEADER KnownHeaders_02; + internal HTTP_KNOWN_HEADER KnownHeaders_03; + internal HTTP_KNOWN_HEADER KnownHeaders_04; + internal HTTP_KNOWN_HEADER KnownHeaders_05; + internal HTTP_KNOWN_HEADER KnownHeaders_06; + internal HTTP_KNOWN_HEADER KnownHeaders_07; + internal HTTP_KNOWN_HEADER KnownHeaders_08; + internal HTTP_KNOWN_HEADER KnownHeaders_09; + internal HTTP_KNOWN_HEADER KnownHeaders_10; + internal HTTP_KNOWN_HEADER KnownHeaders_11; + internal HTTP_KNOWN_HEADER KnownHeaders_12; + internal HTTP_KNOWN_HEADER KnownHeaders_13; + internal HTTP_KNOWN_HEADER KnownHeaders_14; + internal HTTP_KNOWN_HEADER KnownHeaders_15; + internal HTTP_KNOWN_HEADER KnownHeaders_16; + internal HTTP_KNOWN_HEADER KnownHeaders_17; + internal HTTP_KNOWN_HEADER KnownHeaders_18; + internal HTTP_KNOWN_HEADER KnownHeaders_19; + internal HTTP_KNOWN_HEADER KnownHeaders_20; + internal HTTP_KNOWN_HEADER KnownHeaders_21; + internal HTTP_KNOWN_HEADER KnownHeaders_22; + internal HTTP_KNOWN_HEADER KnownHeaders_23; + internal HTTP_KNOWN_HEADER KnownHeaders_24; + internal HTTP_KNOWN_HEADER KnownHeaders_25; + internal HTTP_KNOWN_HEADER KnownHeaders_26; + internal HTTP_KNOWN_HEADER KnownHeaders_27; + internal HTTP_KNOWN_HEADER KnownHeaders_28; + internal HTTP_KNOWN_HEADER KnownHeaders_29; + internal HTTP_KNOWN_HEADER KnownHeaders_30; + internal HTTP_KNOWN_HEADER KnownHeaders_31; + internal HTTP_KNOWN_HEADER KnownHeaders_32; + internal HTTP_KNOWN_HEADER KnownHeaders_33; + internal HTTP_KNOWN_HEADER KnownHeaders_34; + internal HTTP_KNOWN_HEADER KnownHeaders_35; + internal HTTP_KNOWN_HEADER KnownHeaders_36; + internal HTTP_KNOWN_HEADER KnownHeaders_37; + internal HTTP_KNOWN_HEADER KnownHeaders_38; + internal HTTP_KNOWN_HEADER KnownHeaders_39; + internal HTTP_KNOWN_HEADER KnownHeaders_40; + internal HTTP_KNOWN_HEADER KnownHeaders_41; + } + + internal enum HTTP_VERB : int + { + HttpVerbUnparsed = 0, + HttpVerbUnknown = 1, + HttpVerbInvalid = 2, + HttpVerbOPTIONS = 3, + HttpVerbGET = 4, + HttpVerbHEAD = 5, + HttpVerbPOST = 6, + HttpVerbPUT = 7, + HttpVerbDELETE = 8, + HttpVerbTRACE = 9, + HttpVerbCONNECT = 10, + HttpVerbTRACK = 11, + HttpVerbMOVE = 12, + HttpVerbCOPY = 13, + HttpVerbPROPFIND = 14, + HttpVerbPROPPATCH = 15, + HttpVerbMKCOL = 16, + HttpVerbLOCK = 17, + HttpVerbUNLOCK = 18, + HttpVerbSEARCH = 19, + HttpVerbMaximum = 20, + } + + internal static readonly string[] HttpVerbs = new string[] + { + null, + "Unknown", + "Invalid", + "OPTIONS", + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "TRACE", + "CONNECT", + "TRACK", + "MOVE", + "COPY", + "PROPFIND", + "PROPPATCH", + "MKCOL", + "LOCK", + "UNLOCK", + "SEARCH", + }; + + internal enum HTTP_DATA_CHUNK_TYPE : int + { + HttpDataChunkFromMemory = 0, + HttpDataChunkFromFileHandle = 1, + HttpDataChunkFromFragmentCache = 2, + HttpDataChunkMaximum = 3, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_INFO + { + internal HTTP_RESPONSE_INFO_TYPE Type; + internal uint Length; + internal HTTP_MULTIPLE_KNOWN_HEADERS* pInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE + { + internal uint Flags; + internal HTTP_VERSION Version; + internal ushort StatusCode; + internal ushort ReasonLength; + internal sbyte* pReason; + internal HTTP_RESPONSE_HEADERS Headers; + internal ushort EntityChunkCount; + internal HTTP_DATA_CHUNK* pEntityChunks; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_V2 + { + internal HTTP_RESPONSE Response_V1; + internal ushort ResponseInfoCount; + internal HTTP_RESPONSE_INFO* pResponseInfo; + } + + internal enum HTTP_RESPONSE_INFO_FLAGS : uint + { + None = 0, + PreserveOrder = 1, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_MULTIPLE_KNOWN_HEADERS + { + internal HTTP_RESPONSE_HEADER_ID.Enum HeaderId; + internal HTTP_RESPONSE_INFO_FLAGS Flags; + internal ushort KnownHeaderCount; + internal HTTP_KNOWN_HEADER* KnownHeaders; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_AUTH_INFO + { + internal HTTP_AUTH_STATUS AuthStatus; + internal uint SecStatus; + internal uint Flags; + internal HTTP_REQUEST_AUTH_TYPE AuthType; + internal IntPtr AccessToken; + internal uint ContextAttributes; + internal uint PackedContextLength; + internal uint PackedContextType; + internal IntPtr PackedContext; + internal uint MutualAuthDataLength; + internal char* pMutualAuthData; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_INFO + { + internal HTTP_REQUEST_INFO_TYPE InfoType; + internal uint InfoLength; + internal HTTP_REQUEST_AUTH_INFO* pInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST + { + internal uint Flags; + internal ulong ConnectionId; + internal ulong RequestId; + internal ulong UrlContext; + internal HTTP_VERSION Version; + internal HTTP_VERB Verb; + internal ushort UnknownVerbLength; + internal ushort RawUrlLength; + internal sbyte* pUnknownVerb; + internal sbyte* pRawUrl; + internal HTTP_COOKED_URL CookedUrl; + internal HTTP_TRANSPORT_ADDRESS Address; + internal HTTP_REQUEST_HEADERS Headers; + internal ulong BytesReceived; + internal ushort EntityChunkCount; + internal HTTP_DATA_CHUNK* pEntityChunks; + internal ulong RawConnectionId; + internal HTTP_SSL_INFO* pSslInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_V2 + { + internal HTTP_REQUEST Request; + internal ushort RequestInfoCount; + internal HTTP_REQUEST_INFO* pRequestInfo; + } + + internal enum HTTP_AUTH_STATUS + { + HttpAuthStatusSuccess, + HttpAuthStatusNotAuthenticated, + HttpAuthStatusFailure, + } + + internal enum HTTP_REQUEST_AUTH_TYPE + { + HttpRequestAuthTypeNone = 0, + HttpRequestAuthTypeBasic, + HttpRequestAuthTypeDigest, + HttpRequestAuthTypeNTLM, + HttpRequestAuthTypeNegotiate, + HttpRequestAuthTypeKerberos + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_INFO + { + internal HTTP_FLAGS Flags; + internal HTTP_AUTH_TYPES AuthSchemes; + internal bool ReceiveMutualAuth; + internal bool ReceiveContextHandle; + internal bool DisableNTLMCredentialCaching; + internal ulong ExFlags; + HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS DigestParams; + HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS BasicParams; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS + { + internal ushort DomainNameLength; + internal char* DomainName; + internal ushort RealmLength; + internal char* Realm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS + { + ushort RealmLength; + char* Realm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_TOKEN_BINDING_INFO + { + public byte* TokenBinding; + public uint TokenBindingSize; + + public byte* TlsUnique; + public uint TlsUniqueSize; + + public char* KeyType; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_TIMEOUT_LIMIT_INFO + { + internal HTTP_FLAGS Flags; + internal ushort EntityBody; + internal ushort DrainEntityBody; + internal ushort RequestQueue; + internal ushort IdleConnection; + internal ushort HeaderWait; + internal uint MinSendRate; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_BINDING_INFO + { + internal HTTP_FLAGS Flags; + internal IntPtr RequestQueueHandle; + } + + // see http.w for definitions + [Flags] + internal enum HTTP_FLAGS : uint + { + NONE = 0x00000000, + HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY = 0x00000001, + HTTP_RECEIVE_SECURE_CHANNEL_TOKEN = 0x00000001, + HTTP_SEND_RESPONSE_FLAG_DISCONNECT = 0x00000001, + HTTP_SEND_RESPONSE_FLAG_MORE_DATA = 0x00000002, + HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA = 0x00000004, + HTTP_SEND_RESPONSE_FLAG_RAW_HEADER = 0x00000004, + HTTP_SEND_REQUEST_FLAG_MORE_DATA = 0x00000001, + HTTP_PROPERTY_FLAG_PRESENT = 0x00000001, + HTTP_INITIALIZE_SERVER = 0x00000001, + HTTP_INITIALIZE_CBT = 0x00000004, + HTTP_SEND_RESPONSE_FLAG_OPAQUE = 0x00000040, + } + + [Flags] + internal enum HTTP_AUTH_TYPES : uint + { + NONE = 0x00000000, + HTTP_AUTH_ENABLE_BASIC = 0x00000001, + HTTP_AUTH_ENABLE_DIGEST = 0x00000002, + HTTP_AUTH_ENABLE_NTLM = 0x00000004, + HTTP_AUTH_ENABLE_NEGOTIATE = 0x00000008, + HTTP_AUTH_ENABLE_KERBEROS = 0x00000010, + } + + private const int HttpHeaderRequestMaximum = (int)HttpSysRequestHeader.UserAgent + 1; + private const int HttpHeaderResponseMaximum = (int)HttpSysResponseHeader.WwwAuthenticate + 1; + + internal static class HTTP_REQUEST_HEADER_ID + { + internal static string ToString(int position) + { + return _strings[position]; + } + + private static string[] _strings = + { + "Cache-Control", + "Connection", + "Date", + "Keep-Alive", + "Pragma", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Via", + "Warning", + + "Allow", + "Content-Length", + "Content-Type", + "Content-Encoding", + "Content-Language", + "Content-Location", + "Content-MD5", + "Content-Range", + "Expires", + "Last-Modified", + + "Accept", + "Accept-Charset", + "Accept-Encoding", + "Accept-Language", + "Authorization", + "Cookie", + "Expect", + "From", + "Host", + "If-Match", + + "If-Modified-Since", + "If-None-Match", + "If-Range", + "If-Unmodified-Since", + "Max-Forwards", + "Proxy-Authorization", + "Referer", + "Range", + "Te", + "Translate", + "User-Agent", + }; + } + + internal static class HTTP_RESPONSE_HEADER_ID + { + private static string[] _strings = + { + "Cache-Control", + "Connection", + "Date", + "Keep-Alive", + "Pragma", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Via", + "Warning", + + "Allow", + "Content-Length", + "Content-Type", + "Content-Encoding", + "Content-Language", + "Content-Location", + "Content-MD5", + "Content-Range", + "Expires", + "Last-Modified", + + "Accept-Ranges", + "Age", + "ETag", + "Location", + "Proxy-Authenticate", + "Retry-After", + "Server", + "Set-Cookie", + "Vary", + "WWW-Authenticate", + }; + + private static Dictionary _lookupTable = CreateLookupTable(); + + private static Dictionary CreateLookupTable() + { + Dictionary lookupTable = new Dictionary((int)Enum.HttpHeaderResponseMaximum, StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++) + { + lookupTable.Add(_strings[i], i); + } + return lookupTable; + } + + internal static int IndexOfKnownHeader(string HeaderName) + { + int index; + return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1; + } + + internal static string ToString(int position) + { + return _strings[position]; + } + + internal enum Enum + { + HttpHeaderCacheControl = 0, // general-header [section 4.5] + HttpHeaderConnection = 1, // general-header [section 4.5] + HttpHeaderDate = 2, // general-header [section 4.5] + HttpHeaderKeepAlive = 3, // general-header [not in rfc] + HttpHeaderPragma = 4, // general-header [section 4.5] + HttpHeaderTrailer = 5, // general-header [section 4.5] + HttpHeaderTransferEncoding = 6, // general-header [section 4.5] + HttpHeaderUpgrade = 7, // general-header [section 4.5] + HttpHeaderVia = 8, // general-header [section 4.5] + HttpHeaderWarning = 9, // general-header [section 4.5] + + HttpHeaderAllow = 10, // entity-header [section 7.1] + HttpHeaderContentLength = 11, // entity-header [section 7.1] + HttpHeaderContentType = 12, // entity-header [section 7.1] + HttpHeaderContentEncoding = 13, // entity-header [section 7.1] + HttpHeaderContentLanguage = 14, // entity-header [section 7.1] + HttpHeaderContentLocation = 15, // entity-header [section 7.1] + HttpHeaderContentMd5 = 16, // entity-header [section 7.1] + HttpHeaderContentRange = 17, // entity-header [section 7.1] + HttpHeaderExpires = 18, // entity-header [section 7.1] + HttpHeaderLastModified = 19, // entity-header [section 7.1] + + // Response Headers + + HttpHeaderAcceptRanges = 20, // response-header [section 6.2] + HttpHeaderAge = 21, // response-header [section 6.2] + HttpHeaderEtag = 22, // response-header [section 6.2] + HttpHeaderLocation = 23, // response-header [section 6.2] + HttpHeaderProxyAuthenticate = 24, // response-header [section 6.2] + HttpHeaderRetryAfter = 25, // response-header [section 6.2] + HttpHeaderServer = 26, // response-header [section 6.2] + HttpHeaderSetCookie = 27, // response-header [not in rfc] + HttpHeaderVary = 28, // response-header [section 6.2] + HttpHeaderWwwAuthenticate = 29, // response-header [section 6.2] + + HttpHeaderResponseMaximum = 30, + + HttpHeaderMaximum = 41 + } + } + + private static HTTPAPI_VERSION version; + + // This property is used by HttpListener to pass the version structure to the native layer in API + // calls. + + internal static HTTPAPI_VERSION Version + { + get + { + return version; + } + } + + // This property is used by HttpListener to get the Api version in use so that it uses appropriate + // Http APIs. + + internal static HTTP_API_VERSION ApiVersion + { + get + { + if (version.HttpApiMajorVersion == 2 && version.HttpApiMinorVersion == 0) + { + return HTTP_API_VERSION.Version20; + } + else if (version.HttpApiMajorVersion == 1 && version.HttpApiMinorVersion == 0) + { + return HTTP_API_VERSION.Version10; + } + else + { + return HTTP_API_VERSION.Invalid; + } + } + } + + static HttpApi() + { + InitHttpApi(2, 0); + } + + private static void InitHttpApi(ushort majorVersion, ushort minorVersion) + { + version.HttpApiMajorVersion = majorVersion; + version.HttpApiMinorVersion = minorVersion; + + var statusCode = HttpInitialize(version, (uint)HTTP_FLAGS.HTTP_INITIALIZE_SERVER, null); + + supported = statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; + } + + private static volatile bool supported; + internal static bool Supported + { + get + { + return supported; + } + } + + // Server API + + internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob, + int requestOffset, IntPtr originalAddress) + { + // Return value. + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); + long fixup = pMemoryBlob - (byte*)originalAddress; + int index; + + // unknown headers + if (request->Headers.UnknownHeaderCount != 0) + { + HTTP_UNKNOWN_HEADER* pUnknownHeader = (HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders); + for (index = 0; index < request->Headers.UnknownHeaderCount; index++) + { + // For unknown headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will be null. + if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) + { + string headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength); + string headerValue; + if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) + { + headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength); + } + else + { + headerValue = string.Empty; + } + // Note that Http.Sys currently collapses all headers of the same name to a single coma seperated string, + // so we can just call Set. + unknownHeaders[headerName] = headerValue; + } + pUnknownHeader++; + } + } + } + } + + private static string GetKnownHeader(HTTP_REQUEST* request, long fixup, int headerIndex) + { + string header = null; + + HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; + // For known headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will point to empty string ("\0") + if (pKnownHeader->pRawValue != null) + { + header = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength); + } + + return header; + } + + internal static string GetKnownHeader(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, int headerIndex) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + return GetKnownHeader( + (HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress, headerIndex); + } + } + + // This requires the HTTP_REQUEST to still be pinned in its original location. + internal static unsafe string GetVerb(HTTP_REQUEST* request) + { + string verb = null; + + if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnknown && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) + { + verb = HttpVerbs[(int)request->Verb]; + } + else if (request->Verb == HTTP_VERB.HttpVerbUnknown && request->pUnknownVerb != null) + { + verb = HeaderEncoding.GetString(request->pUnknownVerb, request->UnknownVerbLength); + } + + return verb; + } + + internal static uint GetChunks(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, + ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) + { + // Return value. + uint dataRead = 0; + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); + long fixup = pMemoryBlob - (byte*)originalAddress; + + if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) + { + HTTP_DATA_CHUNK* pDataChunk = (HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); + + fixed (byte* pReadBuffer = buffer) + { + byte* pTo = &pReadBuffer[offset]; + + while (dataChunkIndex < request->EntityChunkCount && dataRead < size) + { + if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength) + { + dataChunkOffset = 0; + dataChunkIndex++; + pDataChunk++; + } + else + { + byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup; + + uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset; + if (bytesToRead > (uint)size) + { + bytesToRead = (uint)size; + } + for (uint i = 0; i < bytesToRead; i++) + { + *(pTo++) = *(pFrom++); + } + dataRead += bytesToRead; + dataChunkOffset += bytesToRead; + } + } + } + } + // we're finished. + if (dataChunkIndex == request->EntityChunkCount) + { + dataChunkIndex = -1; + } + } + + return dataRead; + } + + internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); + return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pRemoteAddress); + } + } + + internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); + return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pLocalAddress); + } + } + + internal static SocketAddress GetEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, byte* source) + { + fixed (byte* pMemoryBlob = memoryBlob) + { + IntPtr address = source != null ? + (IntPtr)(pMemoryBlob + requestOffset - (byte*)originalAddress + source) : IntPtr.Zero; + return CopyOutAddress(address); + } + } + + private static SocketAddress CopyOutAddress(IntPtr address) + { + if (address != IntPtr.Zero) + { + ushort addressFamily = *((ushort*)address); + if (addressFamily == (ushort)AddressFamily.InterNetwork) + { + SocketAddress v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize); + fixed (byte* pBuffer = v4address.Buffer) + { + for (int index = 2; index < SocketAddress.IPv4AddressSize; index++) + { + pBuffer[index] = ((byte*)address)[index]; + } + } + return v4address; + } + if (addressFamily == (ushort)AddressFamily.InterNetworkV6) + { + SocketAddress v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize); + fixed (byte* pBuffer = v6address.Buffer) + { + for (int index = 2; index < SocketAddress.IPv6AddressSize; index++) + { + pBuffer[index] = ((byte*)address)[index]; + } + } + return v6address; + } + } + + return null; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs index bcf8890704..8b78d4e14a 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs @@ -35,7 +35,7 @@ namespace Microsoft.Net.Http.Server protected override bool ReleaseHandle() { - return (UnsafeNclNativeMethods.SafeNetHandles.HttpCloseRequestQueue(handle) == + return (HttpApi.HttpCloseRequestQueue(handle) == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); } } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs index 6300ef684b..1bdfafb8f7 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs @@ -55,7 +55,7 @@ namespace Microsoft.Net.Http.Server if (Interlocked.Increment(ref disposed) == 1) { // Closing server session also closes all open url groups under that server session. - return (UnsafeNclNativeMethods.HttpApi.HttpCloseServerSession(serverSessionId) == + return (HttpApi.HttpCloseServerSession(serverSessionId) == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); } } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs b/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs index 6b3ef07665..87b07e5996 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs @@ -28,7 +28,7 @@ namespace Microsoft.Net.Http.Server internal class RequestQueue { private static readonly int BindingInfoSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private readonly UrlGroup _urlGroup; private readonly ILogger _logger; @@ -39,8 +39,8 @@ namespace Microsoft.Net.Http.Server _logger = logger; HttpRequestQueueV2Handle requestQueueHandle = null; - var statusCode = UnsafeNclNativeMethods.SafeNetHandles.HttpCreateRequestQueue( - UnsafeNclNativeMethods.HttpApi.Version, null, null, 0, out requestQueueHandle); + var statusCode = HttpApi.HttpCreateRequestQueue( + HttpApi.Version, null, null, 0, out requestQueueHandle); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { @@ -69,13 +69,13 @@ namespace Microsoft.Net.Http.Server // Set the association between request queue and url group. After this, requests for registered urls will // get delivered to this request queue. - var info = new UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO(); - info.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + var info = new HttpApi.HTTP_BINDING_INFO(); + info.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; info.RequestQueueHandle = Handle.DangerousGetHandle(); var infoptr = new IntPtr(&info); - _urlGroup.SetProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + _urlGroup.SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, infoptr, (uint)BindingInfoSize); } @@ -87,21 +87,21 @@ namespace Microsoft.Net.Http.Server // is fine since http.sys allows to set HttpServerBindingProperty multiple times for valid // Url groups. - var info = new UnsafeNclNativeMethods.HttpApi.HTTP_BINDING_INFO(); - info.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + var info = new HttpApi.HTTP_BINDING_INFO(); + info.Flags = HttpApi.HTTP_FLAGS.NONE; info.RequestQueueHandle = IntPtr.Zero; var infoptr = new IntPtr(&info); - _urlGroup.SetProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + _urlGroup.SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, infoptr, (uint)BindingInfoSize, throwOnError: false); } // The listener must be active for this to work. internal unsafe void SetLengthLimit(long length) { - var result = UnsafeNclNativeMethods.HttpApi.HttpSetRequestQueueProperty(Handle, - UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, + var result = HttpApi.HttpSetRequestQueueProperty(Handle, + HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, new IntPtr((void*)&length), (uint)Marshal.SizeOf(), 0, IntPtr.Zero); if (result != 0) diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs index 1640efb500..9c2a0e846e 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs @@ -25,8 +25,8 @@ namespace Microsoft.Net.Http.Server internal unsafe ServerSession() { ulong serverSessionId = 0; - var statusCode = UnsafeNclNativeMethods.HttpApi.HttpCreateServerSession( - UnsafeNclNativeMethods.HttpApi.Version, &serverSessionId, 0); + var statusCode = HttpApi.HttpCreateServerSession( + HttpApi.Version, &serverSessionId, 0); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs index 08aaeb2973..eeeb1ed395 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs @@ -17,7 +17,7 @@ using System; using System.Runtime.InteropServices; -using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods.HttpApi; +using static Microsoft.Net.Http.Server.HttpApi; using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods.TokenBinding; namespace Microsoft.Net.Http.Server diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index b9e2c71f72..0fd9a632b7 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -22,17 +22,13 @@ //------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { internal static unsafe class UnsafeNclNativeMethods { - private const string HTTPAPI = "httpapi.dll"; - #if NETSTANDARD1_3 private const string sspicli_LIB = "sspicli.dll"; private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; @@ -63,13 +59,6 @@ namespace Microsoft.Net.Http.Server internal const uint ERROR_CONNECTION_INVALID = 1229; } -#if NETSTANDARD1_3 - [DllImport(api_ms_win_core_processthreads_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] -#endif - internal static extern uint GetCurrentThreadId(); - #if NETSTANDARD1_3 [DllImport(api_ms_win_core_io_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] #else @@ -140,13 +129,6 @@ namespace Microsoft.Net.Http.Server [In] ContextAttribute attribute, [In] void* buffer); - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern unsafe uint HttpCreateRequestQueue(HttpApi.HTTPAPI_VERSION version, string pName, - Microsoft.Net.Http.Server.UnsafeNclNativeMethods.SECURITY_ATTRIBUTES pSecurityAttributes, uint flags, out HttpRequestQueueV2Handle pReqQueueHandle); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); - #if NETSTANDARD1_3 [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] #else @@ -191,1055 +173,6 @@ namespace Microsoft.Net.Http.Server internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); } - internal static unsafe class HttpApi - { - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpInitialize(HTTPAPI_VERSION version, uint flags, void* pReserved); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpReceiveRequestEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, IntPtr pEntityBuffer, uint entityBufferLength, out uint bytesReturned, SafeNativeOverlapped pOverlapped); - - [DllImport(HTTPAPI, EntryPoint = "HttpReceiveRequestEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpReceiveRequestEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, void* pEntityBuffer, uint entityBufferLength, out uint bytesReturned, [In] SafeHandle pOverlapped); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, HTTP_SSL_CLIENT_CERT_INFO* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, byte* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped); - - [SuppressMessage("Microsoft.Interoperability", "CA1415:DeclarePInvokesCorrectly", Justification = "NativeOverlapped is now wrapped by SafeNativeOverlapped")] - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpReceiveHttpRequest(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_REQUEST* pRequestBuffer, uint requestBufferLength, uint* pBytesReturned, SafeNativeOverlapped pOverlapped); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2* pHttpResponse, HTTP_CACHE_POLICY* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK* pEntityChunks, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpCancelHttpRequest(SafeHandle requestQueueHandle, ulong requestId, IntPtr pOverlapped); - - [DllImport(HTTPAPI, EntryPoint = "HttpSendResponseEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSendResponseEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, IntPtr pEntityChunks, out uint pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeHandle pOverlapped, IntPtr pLogData); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpWaitForDisconnectEx(SafeHandle requestQueueHandle, ulong connectionId, uint reserved, SafeNativeOverlapped overlapped); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpCreateServerSession(HTTPAPI_VERSION version, ulong* serverSessionId, uint reserved); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpCreateUrlGroup(ulong serverSessionId, ulong* urlGroupId, uint reserved); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern uint HttpAddUrlToUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, ulong context, uint pReserved); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSetUrlGroupProperty(ulong urlGroupId, HTTP_SERVER_PROPERTY serverProperty, IntPtr pPropertyInfo, uint propertyInfoLength); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern uint HttpRemoveUrlFromUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, uint flags); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpCloseServerSession(ulong serverSessionId); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpCloseUrlGroup(ulong urlGroupId); - - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSetRequestQueueProperty(SafeHandle requestQueueHandle, HTTP_SERVER_PROPERTY serverProperty, IntPtr pPropertyInfo, uint propertyInfoLength, uint reserved, IntPtr pReserved); - - internal enum HTTP_API_VERSION - { - Invalid, - Version10, - Version20, - } - - // see http.w for definitions - internal enum HTTP_SERVER_PROPERTY - { - HttpServerAuthenticationProperty, - HttpServerLoggingProperty, - HttpServerQosProperty, - HttpServerTimeoutsProperty, - HttpServerQueueLengthProperty, - HttpServerStateProperty, - HttpServer503VerbosityProperty, - HttpServerBindingProperty, - HttpServerExtendedAuthenticationProperty, - HttpServerListenEndpointProperty, - HttpServerChannelBindProperty, - HttpServerProtectionLevelProperty, - } - - // Currently only one request info type is supported but the enum is for future extensibility. - - internal enum HTTP_REQUEST_INFO_TYPE - { - HttpRequestInfoTypeAuth, - HttpRequestInfoTypeChannelBind, - HttpRequestInfoTypeSslProtocol, - HttpRequestInfoTypeSslTokenBinding - } - - internal enum HTTP_RESPONSE_INFO_TYPE - { - HttpResponseInfoTypeMultipleKnownHeaders, - HttpResponseInfoTypeAuthenticationProperty, - HttpResponseInfoTypeQosProperty, - } - - internal enum HTTP_TIMEOUT_TYPE - { - EntityBody, - DrainEntityBody, - RequestQueue, - IdleConnection, - HeaderWait, - MinSendRate, - } - - internal const int MaxTimeout = 6; - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_VERSION - { - internal ushort MajorVersion; - internal ushort MinorVersion; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_KNOWN_HEADER - { - internal ushort RawValueLength; - internal sbyte* pRawValue; - } - - [StructLayout(LayoutKind.Explicit)] - internal struct HTTP_DATA_CHUNK - { - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used natively")] - [FieldOffset(0)] - internal HTTP_DATA_CHUNK_TYPE DataChunkType; - - [FieldOffset(8)] - internal FromMemory fromMemory; - - [FieldOffset(8)] - internal FromFileHandle fromFile; - } - - [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable", - Justification = "This type does not own the native buffer")] - [StructLayout(LayoutKind.Sequential)] - internal struct FromMemory - { - // 4 bytes for 32bit, 8 bytes for 64bit - internal IntPtr pBuffer; - internal uint BufferLength; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct FromFileHandle - { - internal ulong offset; - internal ulong count; - internal IntPtr fileHandle; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTPAPI_VERSION - { - internal ushort HttpApiMajorVersion; - internal ushort HttpApiMinorVersion; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_COOKED_URL - { - internal ushort FullUrlLength; - internal ushort HostLength; - internal ushort AbsPathLength; - internal ushort QueryStringLength; - internal ushort* pFullUrl; - internal ushort* pHost; - internal ushort* pAbsPath; - internal ushort* pQueryString; - } - - // Only cache unauthorized GETs + HEADs. - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_CACHE_POLICY - { - internal HTTP_CACHE_POLICY_TYPE Policy; - internal uint SecondsToLive; - } - - internal enum HTTP_CACHE_POLICY_TYPE : int - { - HttpCachePolicyNocache = 0, - HttpCachePolicyUserInvalidates = 1, - HttpCachePolicyTimeToLive = 2, - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SOCKADDR - { - internal ushort sa_family; - internal byte sa_data; - internal byte sa_data_02; - internal byte sa_data_03; - internal byte sa_data_04; - internal byte sa_data_05; - internal byte sa_data_06; - internal byte sa_data_07; - internal byte sa_data_08; - internal byte sa_data_09; - internal byte sa_data_10; - internal byte sa_data_11; - internal byte sa_data_12; - internal byte sa_data_13; - internal byte sa_data_14; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_TRANSPORT_ADDRESS - { - internal SOCKADDR* pRemoteAddress; - internal SOCKADDR* pLocalAddress; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SSL_CLIENT_CERT_INFO - { - internal uint CertFlags; - internal uint CertEncodedSize; - internal byte* pCertEncoded; - internal void* Token; - internal byte CertDeniedByMapper; - } - - internal enum HTTP_SERVICE_BINDING_TYPE : uint - { - HttpServiceBindingTypeNone = 0, - HttpServiceBindingTypeW, - HttpServiceBindingTypeA - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SERVICE_BINDING_BASE - { - internal HTTP_SERVICE_BINDING_TYPE Type; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_CHANNEL_BIND_STATUS - { - internal IntPtr ServiceName; - internal IntPtr ChannelToken; - internal uint ChannelTokenSize; - internal uint Flags; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_UNKNOWN_HEADER - { - internal ushort NameLength; - internal ushort RawValueLength; - internal sbyte* pName; - internal sbyte* pRawValue; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SSL_INFO - { - internal ushort ServerCertKeySize; - internal ushort ConnectionKeySize; - internal uint ServerCertIssuerSize; - internal uint ServerCertSubjectSize; - internal sbyte* pServerCertIssuer; - internal sbyte* pServerCertSubject; - internal HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo; - internal uint SslClientCertNegotiated; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_RESPONSE_HEADERS - { - internal ushort UnknownHeaderCount; - internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; - internal ushort TrailerCount; - internal HTTP_UNKNOWN_HEADER* pTrailers; - internal HTTP_KNOWN_HEADER KnownHeaders; - internal HTTP_KNOWN_HEADER KnownHeaders_02; - internal HTTP_KNOWN_HEADER KnownHeaders_03; - internal HTTP_KNOWN_HEADER KnownHeaders_04; - internal HTTP_KNOWN_HEADER KnownHeaders_05; - internal HTTP_KNOWN_HEADER KnownHeaders_06; - internal HTTP_KNOWN_HEADER KnownHeaders_07; - internal HTTP_KNOWN_HEADER KnownHeaders_08; - internal HTTP_KNOWN_HEADER KnownHeaders_09; - internal HTTP_KNOWN_HEADER KnownHeaders_10; - internal HTTP_KNOWN_HEADER KnownHeaders_11; - internal HTTP_KNOWN_HEADER KnownHeaders_12; - internal HTTP_KNOWN_HEADER KnownHeaders_13; - internal HTTP_KNOWN_HEADER KnownHeaders_14; - internal HTTP_KNOWN_HEADER KnownHeaders_15; - internal HTTP_KNOWN_HEADER KnownHeaders_16; - internal HTTP_KNOWN_HEADER KnownHeaders_17; - internal HTTP_KNOWN_HEADER KnownHeaders_18; - internal HTTP_KNOWN_HEADER KnownHeaders_19; - internal HTTP_KNOWN_HEADER KnownHeaders_20; - internal HTTP_KNOWN_HEADER KnownHeaders_21; - internal HTTP_KNOWN_HEADER KnownHeaders_22; - internal HTTP_KNOWN_HEADER KnownHeaders_23; - internal HTTP_KNOWN_HEADER KnownHeaders_24; - internal HTTP_KNOWN_HEADER KnownHeaders_25; - internal HTTP_KNOWN_HEADER KnownHeaders_26; - internal HTTP_KNOWN_HEADER KnownHeaders_27; - internal HTTP_KNOWN_HEADER KnownHeaders_28; - internal HTTP_KNOWN_HEADER KnownHeaders_29; - internal HTTP_KNOWN_HEADER KnownHeaders_30; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_HEADERS - { - internal ushort UnknownHeaderCount; - internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; - internal ushort TrailerCount; - internal HTTP_UNKNOWN_HEADER* pTrailers; - internal HTTP_KNOWN_HEADER KnownHeaders; - internal HTTP_KNOWN_HEADER KnownHeaders_02; - internal HTTP_KNOWN_HEADER KnownHeaders_03; - internal HTTP_KNOWN_HEADER KnownHeaders_04; - internal HTTP_KNOWN_HEADER KnownHeaders_05; - internal HTTP_KNOWN_HEADER KnownHeaders_06; - internal HTTP_KNOWN_HEADER KnownHeaders_07; - internal HTTP_KNOWN_HEADER KnownHeaders_08; - internal HTTP_KNOWN_HEADER KnownHeaders_09; - internal HTTP_KNOWN_HEADER KnownHeaders_10; - internal HTTP_KNOWN_HEADER KnownHeaders_11; - internal HTTP_KNOWN_HEADER KnownHeaders_12; - internal HTTP_KNOWN_HEADER KnownHeaders_13; - internal HTTP_KNOWN_HEADER KnownHeaders_14; - internal HTTP_KNOWN_HEADER KnownHeaders_15; - internal HTTP_KNOWN_HEADER KnownHeaders_16; - internal HTTP_KNOWN_HEADER KnownHeaders_17; - internal HTTP_KNOWN_HEADER KnownHeaders_18; - internal HTTP_KNOWN_HEADER KnownHeaders_19; - internal HTTP_KNOWN_HEADER KnownHeaders_20; - internal HTTP_KNOWN_HEADER KnownHeaders_21; - internal HTTP_KNOWN_HEADER KnownHeaders_22; - internal HTTP_KNOWN_HEADER KnownHeaders_23; - internal HTTP_KNOWN_HEADER KnownHeaders_24; - internal HTTP_KNOWN_HEADER KnownHeaders_25; - internal HTTP_KNOWN_HEADER KnownHeaders_26; - internal HTTP_KNOWN_HEADER KnownHeaders_27; - internal HTTP_KNOWN_HEADER KnownHeaders_28; - internal HTTP_KNOWN_HEADER KnownHeaders_29; - internal HTTP_KNOWN_HEADER KnownHeaders_30; - internal HTTP_KNOWN_HEADER KnownHeaders_31; - internal HTTP_KNOWN_HEADER KnownHeaders_32; - internal HTTP_KNOWN_HEADER KnownHeaders_33; - internal HTTP_KNOWN_HEADER KnownHeaders_34; - internal HTTP_KNOWN_HEADER KnownHeaders_35; - internal HTTP_KNOWN_HEADER KnownHeaders_36; - internal HTTP_KNOWN_HEADER KnownHeaders_37; - internal HTTP_KNOWN_HEADER KnownHeaders_38; - internal HTTP_KNOWN_HEADER KnownHeaders_39; - internal HTTP_KNOWN_HEADER KnownHeaders_40; - internal HTTP_KNOWN_HEADER KnownHeaders_41; - } - - internal enum HTTP_VERB : int - { - HttpVerbUnparsed = 0, - HttpVerbUnknown = 1, - HttpVerbInvalid = 2, - HttpVerbOPTIONS = 3, - HttpVerbGET = 4, - HttpVerbHEAD = 5, - HttpVerbPOST = 6, - HttpVerbPUT = 7, - HttpVerbDELETE = 8, - HttpVerbTRACE = 9, - HttpVerbCONNECT = 10, - HttpVerbTRACK = 11, - HttpVerbMOVE = 12, - HttpVerbCOPY = 13, - HttpVerbPROPFIND = 14, - HttpVerbPROPPATCH = 15, - HttpVerbMKCOL = 16, - HttpVerbLOCK = 17, - HttpVerbUNLOCK = 18, - HttpVerbSEARCH = 19, - HttpVerbMaximum = 20, - } - - internal static readonly string[] HttpVerbs = new string[] - { - null, - "Unknown", - "Invalid", - "OPTIONS", - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "TRACE", - "CONNECT", - "TRACK", - "MOVE", - "COPY", - "PROPFIND", - "PROPPATCH", - "MKCOL", - "LOCK", - "UNLOCK", - "SEARCH", - }; - - internal enum HTTP_DATA_CHUNK_TYPE : int - { - HttpDataChunkFromMemory = 0, - HttpDataChunkFromFileHandle = 1, - HttpDataChunkFromFragmentCache = 2, - HttpDataChunkMaximum = 3, - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_RESPONSE_INFO - { - internal HTTP_RESPONSE_INFO_TYPE Type; - internal uint Length; - internal HTTP_MULTIPLE_KNOWN_HEADERS* pInfo; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_RESPONSE - { - internal uint Flags; - internal HTTP_VERSION Version; - internal ushort StatusCode; - internal ushort ReasonLength; - internal sbyte* pReason; - internal HTTP_RESPONSE_HEADERS Headers; - internal ushort EntityChunkCount; - internal HTTP_DATA_CHUNK* pEntityChunks; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_RESPONSE_V2 - { - internal HTTP_RESPONSE Response_V1; - internal ushort ResponseInfoCount; - internal HTTP_RESPONSE_INFO* pResponseInfo; - } - - internal enum HTTP_RESPONSE_INFO_FLAGS : uint - { - None = 0, - PreserveOrder = 1, - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_MULTIPLE_KNOWN_HEADERS - { - internal HTTP_RESPONSE_HEADER_ID.Enum HeaderId; - internal HTTP_RESPONSE_INFO_FLAGS Flags; - internal ushort KnownHeaderCount; - internal HTTP_KNOWN_HEADER* KnownHeaders; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_AUTH_INFO - { - internal HTTP_AUTH_STATUS AuthStatus; - internal uint SecStatus; - internal uint Flags; - internal HTTP_REQUEST_AUTH_TYPE AuthType; - internal IntPtr AccessToken; - internal uint ContextAttributes; - internal uint PackedContextLength; - internal uint PackedContextType; - internal IntPtr PackedContext; - internal uint MutualAuthDataLength; - internal char* pMutualAuthData; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_INFO - { - internal HTTP_REQUEST_INFO_TYPE InfoType; - internal uint InfoLength; - internal HTTP_REQUEST_AUTH_INFO* pInfo; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST - { - internal uint Flags; - internal ulong ConnectionId; - internal ulong RequestId; - internal ulong UrlContext; - internal HTTP_VERSION Version; - internal HTTP_VERB Verb; - internal ushort UnknownVerbLength; - internal ushort RawUrlLength; - internal sbyte* pUnknownVerb; - internal sbyte* pRawUrl; - internal HTTP_COOKED_URL CookedUrl; - internal HTTP_TRANSPORT_ADDRESS Address; - internal HTTP_REQUEST_HEADERS Headers; - internal ulong BytesReceived; - internal ushort EntityChunkCount; - internal HTTP_DATA_CHUNK* pEntityChunks; - internal ulong RawConnectionId; - internal HTTP_SSL_INFO* pSslInfo; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_V2 - { - internal HTTP_REQUEST Request; - internal ushort RequestInfoCount; - internal HTTP_REQUEST_INFO* pRequestInfo; - } - - internal enum HTTP_AUTH_STATUS - { - HttpAuthStatusSuccess, - HttpAuthStatusNotAuthenticated, - HttpAuthStatusFailure, - } - - internal enum HTTP_REQUEST_AUTH_TYPE - { - HttpRequestAuthTypeNone = 0, - HttpRequestAuthTypeBasic, - HttpRequestAuthTypeDigest, - HttpRequestAuthTypeNTLM, - HttpRequestAuthTypeNegotiate, - HttpRequestAuthTypeKerberos - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SERVER_AUTHENTICATION_INFO - { - internal HTTP_FLAGS Flags; - internal HTTP_AUTH_TYPES AuthSchemes; - internal bool ReceiveMutualAuth; - internal bool ReceiveContextHandle; - internal bool DisableNTLMCredentialCaching; - internal ulong ExFlags; - HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS DigestParams; - HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS BasicParams; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS - { - internal ushort DomainNameLength; - internal char* DomainName; - internal ushort RealmLength; - internal char* Realm; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS - { - ushort RealmLength; - char* Realm; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_TOKEN_BINDING_INFO - { - public byte* TokenBinding; - public uint TokenBindingSize; - - public byte* TlsUnique; - public uint TlsUniqueSize; - - public char* KeyType; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_TIMEOUT_LIMIT_INFO - { - internal HTTP_FLAGS Flags; - internal ushort EntityBody; - internal ushort DrainEntityBody; - internal ushort RequestQueue; - internal ushort IdleConnection; - internal ushort HeaderWait; - internal uint MinSendRate; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_BINDING_INFO - { - internal HTTP_FLAGS Flags; - internal IntPtr RequestQueueHandle; - } - - // see http.w for definitions - [Flags] - internal enum HTTP_FLAGS : uint - { - NONE = 0x00000000, - HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY = 0x00000001, - HTTP_RECEIVE_SECURE_CHANNEL_TOKEN = 0x00000001, - HTTP_SEND_RESPONSE_FLAG_DISCONNECT = 0x00000001, - HTTP_SEND_RESPONSE_FLAG_MORE_DATA = 0x00000002, - HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA = 0x00000004, - HTTP_SEND_RESPONSE_FLAG_RAW_HEADER = 0x00000004, - HTTP_SEND_REQUEST_FLAG_MORE_DATA = 0x00000001, - HTTP_PROPERTY_FLAG_PRESENT = 0x00000001, - HTTP_INITIALIZE_SERVER = 0x00000001, - HTTP_INITIALIZE_CBT = 0x00000004, - HTTP_SEND_RESPONSE_FLAG_OPAQUE = 0x00000040, - } - - [Flags] - internal enum HTTP_AUTH_TYPES : uint - { - NONE = 0x00000000, - HTTP_AUTH_ENABLE_BASIC = 0x00000001, - HTTP_AUTH_ENABLE_DIGEST = 0x00000002, - HTTP_AUTH_ENABLE_NTLM = 0x00000004, - HTTP_AUTH_ENABLE_NEGOTIATE = 0x00000008, - HTTP_AUTH_ENABLE_KERBEROS = 0x00000010, - } - - private const int HttpHeaderRequestMaximum = (int)HttpSysRequestHeader.UserAgent + 1; - private const int HttpHeaderResponseMaximum = (int)HttpSysResponseHeader.WwwAuthenticate + 1; - - internal static class HTTP_REQUEST_HEADER_ID - { - internal static string ToString(int position) - { - return _strings[position]; - } - - private static string[] _strings = - { - "Cache-Control", - "Connection", - "Date", - "Keep-Alive", - "Pragma", - "Trailer", - "Transfer-Encoding", - "Upgrade", - "Via", - "Warning", - - "Allow", - "Content-Length", - "Content-Type", - "Content-Encoding", - "Content-Language", - "Content-Location", - "Content-MD5", - "Content-Range", - "Expires", - "Last-Modified", - - "Accept", - "Accept-Charset", - "Accept-Encoding", - "Accept-Language", - "Authorization", - "Cookie", - "Expect", - "From", - "Host", - "If-Match", - - "If-Modified-Since", - "If-None-Match", - "If-Range", - "If-Unmodified-Since", - "Max-Forwards", - "Proxy-Authorization", - "Referer", - "Range", - "Te", - "Translate", - "User-Agent", - }; - } - - internal static class HTTP_RESPONSE_HEADER_ID - { - private static string[] _strings = - { - "Cache-Control", - "Connection", - "Date", - "Keep-Alive", - "Pragma", - "Trailer", - "Transfer-Encoding", - "Upgrade", - "Via", - "Warning", - - "Allow", - "Content-Length", - "Content-Type", - "Content-Encoding", - "Content-Language", - "Content-Location", - "Content-MD5", - "Content-Range", - "Expires", - "Last-Modified", - - "Accept-Ranges", - "Age", - "ETag", - "Location", - "Proxy-Authenticate", - "Retry-After", - "Server", - "Set-Cookie", - "Vary", - "WWW-Authenticate", - }; - - private static Dictionary _lookupTable = CreateLookupTable(); - - private static Dictionary CreateLookupTable() - { - Dictionary lookupTable = new Dictionary((int)Enum.HttpHeaderResponseMaximum, StringComparer.OrdinalIgnoreCase); - for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++) - { - lookupTable.Add(_strings[i], i); - } - return lookupTable; - } - - internal static int IndexOfKnownHeader(string HeaderName) - { - int index; - return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1; - } - - internal static string ToString(int position) - { - return _strings[position]; - } - - internal enum Enum - { - HttpHeaderCacheControl = 0, // general-header [section 4.5] - HttpHeaderConnection = 1, // general-header [section 4.5] - HttpHeaderDate = 2, // general-header [section 4.5] - HttpHeaderKeepAlive = 3, // general-header [not in rfc] - HttpHeaderPragma = 4, // general-header [section 4.5] - HttpHeaderTrailer = 5, // general-header [section 4.5] - HttpHeaderTransferEncoding = 6, // general-header [section 4.5] - HttpHeaderUpgrade = 7, // general-header [section 4.5] - HttpHeaderVia = 8, // general-header [section 4.5] - HttpHeaderWarning = 9, // general-header [section 4.5] - - HttpHeaderAllow = 10, // entity-header [section 7.1] - HttpHeaderContentLength = 11, // entity-header [section 7.1] - HttpHeaderContentType = 12, // entity-header [section 7.1] - HttpHeaderContentEncoding = 13, // entity-header [section 7.1] - HttpHeaderContentLanguage = 14, // entity-header [section 7.1] - HttpHeaderContentLocation = 15, // entity-header [section 7.1] - HttpHeaderContentMd5 = 16, // entity-header [section 7.1] - HttpHeaderContentRange = 17, // entity-header [section 7.1] - HttpHeaderExpires = 18, // entity-header [section 7.1] - HttpHeaderLastModified = 19, // entity-header [section 7.1] - - // Response Headers - - HttpHeaderAcceptRanges = 20, // response-header [section 6.2] - HttpHeaderAge = 21, // response-header [section 6.2] - HttpHeaderEtag = 22, // response-header [section 6.2] - HttpHeaderLocation = 23, // response-header [section 6.2] - HttpHeaderProxyAuthenticate = 24, // response-header [section 6.2] - HttpHeaderRetryAfter = 25, // response-header [section 6.2] - HttpHeaderServer = 26, // response-header [section 6.2] - HttpHeaderSetCookie = 27, // response-header [not in rfc] - HttpHeaderVary = 28, // response-header [section 6.2] - HttpHeaderWwwAuthenticate = 29, // response-header [section 6.2] - - HttpHeaderResponseMaximum = 30, - - HttpHeaderMaximum = 41 - } - } - - private static HTTPAPI_VERSION version; - - // This property is used by HttpListener to pass the version structure to the native layer in API - // calls. - - internal static HTTPAPI_VERSION Version - { - get - { - return version; - } - } - - // This property is used by HttpListener to get the Api version in use so that it uses appropriate - // Http APIs. - - internal static HTTP_API_VERSION ApiVersion - { - get - { - if (version.HttpApiMajorVersion == 2 && version.HttpApiMinorVersion == 0) - { - return HTTP_API_VERSION.Version20; - } - else if (version.HttpApiMajorVersion == 1 && version.HttpApiMinorVersion == 0) - { - return HTTP_API_VERSION.Version10; - } - else - { - return HTTP_API_VERSION.Invalid; - } - } - } - - static HttpApi() - { - InitHttpApi(2, 0); - } - - private static void InitHttpApi(ushort majorVersion, ushort minorVersion) - { - version.HttpApiMajorVersion = majorVersion; - version.HttpApiMinorVersion = minorVersion; - - var statusCode = HttpApi.HttpInitialize(version, (uint)HTTP_FLAGS.HTTP_INITIALIZE_SERVER, null); - - supported = statusCode == ErrorCodes.ERROR_SUCCESS; - } - - private static volatile bool supported; - internal static bool Supported - { - get - { - return supported; - } - } - - // Server API - - internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob, - int requestOffset, IntPtr originalAddress) - { - // Return value. - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - long fixup = pMemoryBlob - (byte*)originalAddress; - int index; - - // unknown headers - if (request->Headers.UnknownHeaderCount != 0) - { - HTTP_UNKNOWN_HEADER* pUnknownHeader = (HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders); - for (index = 0; index < request->Headers.UnknownHeaderCount; index++) - { - // For unknown headers, when header value is empty, RawValueLength will be 0 and - // pRawValue will be null. - if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) - { - string headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength); - string headerValue; - if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) - { - headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength); - } - else - { - headerValue = string.Empty; - } - // Note that Http.Sys currently collapses all headers of the same name to a single coma seperated string, - // so we can just call Set. - unknownHeaders[headerName] = headerValue; - } - pUnknownHeader++; - } - } - } - } - - private static string GetKnownHeader(HTTP_REQUEST* request, long fixup, int headerIndex) - { - string header = null; - - HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; - // For known headers, when header value is empty, RawValueLength will be 0 and - // pRawValue will point to empty string ("\0") - if (pKnownHeader->pRawValue != null) - { - header = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength); - } - - return header; - } - - internal static string GetKnownHeader(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, int headerIndex) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - return GetKnownHeader( - (HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress, headerIndex); - } - } - - // This requires the HTTP_REQUEST to still be pinned in its original location. - internal static unsafe string GetVerb(HTTP_REQUEST* request) - { - string verb = null; - - if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnknown && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) - { - verb = HttpVerbs[(int)request->Verb]; - } - else if (request->Verb == HTTP_VERB.HttpVerbUnknown && request->pUnknownVerb != null) - { - verb = HeaderEncoding.GetString(request->pUnknownVerb, request->UnknownVerbLength); - } - - return verb; - } - - internal static uint GetChunks(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, - ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) - { - // Return value. - uint dataRead = 0; - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - long fixup = pMemoryBlob - (byte*)originalAddress; - - if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) - { - HTTP_DATA_CHUNK* pDataChunk = (HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); - - fixed (byte* pReadBuffer = buffer) - { - byte* pTo = &pReadBuffer[offset]; - - while (dataChunkIndex < request->EntityChunkCount && dataRead < size) - { - if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength) - { - dataChunkOffset = 0; - dataChunkIndex++; - pDataChunk++; - } - else - { - byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup; - - uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset; - if (bytesToRead > (uint)size) - { - bytesToRead = (uint)size; - } - for (uint i = 0; i < bytesToRead; i++) - { - *(pTo++) = *(pFrom++); - } - dataRead += bytesToRead; - dataChunkOffset += bytesToRead; - } - } - } - } - // we're finished. - if (dataChunkIndex == request->EntityChunkCount) - { - dataChunkIndex = -1; - } - } - - return dataRead; - } - - internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pRemoteAddress); - } - } - - internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pLocalAddress); - } - } - - internal static SocketAddress GetEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, byte* source) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - IntPtr address = source != null ? - (IntPtr)(pMemoryBlob + requestOffset - (byte*)originalAddress + source) : IntPtr.Zero; - return CopyOutAddress(address); - } - } - - private static SocketAddress CopyOutAddress(IntPtr address) - { - if (address != IntPtr.Zero) - { - ushort addressFamily = *((ushort*)address); - if (addressFamily == (ushort)AddressFamily.InterNetwork) - { - SocketAddress v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize); - fixed (byte* pBuffer = v4address.Buffer) - { - for (int index = 2; index < SocketAddress.IPv4AddressSize; index++) - { - pBuffer[index] = ((byte*)address)[index]; - } - } - return v4address; - } - if (addressFamily == (ushort)AddressFamily.InterNetworkV6) - { - SocketAddress v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize); - fixed (byte* pBuffer = v6address.Buffer) - { - for (int index = 2; index < SocketAddress.IPv6AddressSize; index++) - { - pBuffer[index] = ((byte*)address)[index]; - } - } - return v6address; - } - } - - return null; - } - } - // from tokenbinding.h internal static class TokenBinding { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs index cb4af099df..385c7c61fa 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs @@ -33,7 +33,7 @@ namespace Microsoft.Net.Http.Server _logger = logger; ulong urlGroupId = 0; - var statusCode = UnsafeNclNativeMethods.HttpApi.HttpCreateUrlGroup( + var statusCode = HttpApi.HttpCreateUrlGroup( _serverSession.Id.DangerousGetServerSessionId(), &urlGroupId, 0); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) @@ -47,11 +47,11 @@ namespace Microsoft.Net.Http.Server internal ulong Id { get; private set; } - internal void SetProperty(UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) + internal void SetProperty(HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) { Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); - var statusCode = UnsafeNclNativeMethods.HttpApi.HttpSetUrlGroupProperty(Id, property, info, infosize); + var statusCode = HttpApi.HttpSetUrlGroupProperty(Id, property, info, infosize); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { @@ -68,7 +68,7 @@ namespace Microsoft.Net.Http.Server { LogHelper.LogInfo(_logger, "Listening on prefix: " + uriPrefix); - var statusCode = UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup(Id, uriPrefix, (ulong)contextId, 0); + var statusCode = HttpApi.HttpAddUrlToUrlGroup(Id, uriPrefix, (ulong)contextId, 0); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { @@ -87,7 +87,7 @@ namespace Microsoft.Net.Http.Server { LogHelper.LogInfo(_logger, "Stop listening on prefix: " + uriPrefix); - var statusCode = UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup(Id, uriPrefix, 0); + var statusCode = HttpApi.HttpRemoveUrlFromUrlGroup(Id, uriPrefix, 0); if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) { @@ -107,7 +107,7 @@ namespace Microsoft.Net.Http.Server Debug.Assert(Id != 0, "HttpCloseUrlGroup called with invalid url group id"); - uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpCloseUrlGroup(Id); + uint statusCode = HttpApi.HttpCloseUrlGroup(Id); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs index 63df5bdc89..f3c60389bb 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs @@ -43,11 +43,11 @@ namespace Microsoft.Net.Http.Server private const uint CertBoblSize = 1500; private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(WaitCallback); private static readonly int RequestChannelBindStatusSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private SafeNativeOverlapped _overlapped; private byte[] _backingBuffer; - private UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* _memoryBlob; + private HttpApi.HTTP_SSL_CLIENT_CERT_INFO* _memoryBlob; private uint _size; private TaskCompletionSource _tcs; private RequestContext _requestContext; @@ -124,7 +124,7 @@ namespace Microsoft.Net.Http.Server } } - private UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* RequestBlob + private HttpApi.HTTP_SSL_CLIENT_CERT_INFO* RequestBlob { get { @@ -154,7 +154,7 @@ namespace Microsoft.Net.Http.Server var boundHandle = RequestContext.Server.RequestQueue.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer)); - _memoryBlob = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); + _memoryBlob = (HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); } // When you use netsh to configure HTTP.SYS with clientcertnegotiation = enable @@ -185,10 +185,10 @@ namespace Microsoft.Net.Http.Server uint bytesReceived = 0; uint statusCode = - UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( + HttpApi.HttpReceiveClientCertificate( RequestQueueHandle, RequestContext.Request.UConnectionId, - (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, + (uint)HttpApi.HTTP_FLAGS.NONE, RequestBlob, size, &bytesReceived, @@ -196,7 +196,7 @@ namespace Microsoft.Net.Http.Server if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) { - UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = RequestBlob; + HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = RequestBlob; size = bytesReceived + pClientCertInfo->CertEncodedSize; Reset(size); retry = true; @@ -259,15 +259,15 @@ namespace Microsoft.Net.Http.Server // return the size of the initial cert structure. To get the full size, // we need to add the certificate encoding size as well. - UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob; + HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob; asyncResult.Reset(numBytes + pClientCertInfo->CertEncodedSize); uint bytesReceived = 0; errorCode = - UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( + HttpApi.HttpReceiveClientCertificate( requestContext.Server.RequestQueue.Handle, requestContext.Request.UConnectionId, - (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, + (uint)HttpApi.HTTP_FLAGS.NONE, asyncResult._memoryBlob, asyncResult._size, &bytesReceived, @@ -291,7 +291,7 @@ namespace Microsoft.Net.Http.Server } else { - UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult._memoryBlob; + HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult._memoryBlob; if (pClientCertInfo == null) { asyncResult.Complete(0, null); @@ -391,10 +391,10 @@ namespace Microsoft.Net.Http.Server { // Http.sys team: ServiceName will always be null if // HTTP_RECEIVE_SECURE_CHANNEL_TOKEN flag is set. - statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( + statusCode = HttpApi.HttpReceiveClientCertificate( requestQueue.Handle, connectionId, - (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN, + (uint)HttpApi.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN, blobPtr, (uint)size, &bytesReceived, @@ -438,7 +438,7 @@ namespace Microsoft.Net.Http.Server private static int GetTokenOffsetFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); - IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); + IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); Debug.Assert(tokenPointer != IntPtr.Zero); return (int)IntPtrHelper.Subtract(tokenPointer, blob); } @@ -446,7 +446,7 @@ namespace Microsoft.Net.Http.Server private static int GetTokenSizeFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); - return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); + return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 49355872f6..5072342c42 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server { private const int DefaultBufferSize = 4096; private const int AlignmentPadding = 8; - private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* _memoryBlob; + private HttpApi.HTTP_REQUEST* _memoryBlob; private IntPtr _originalBlobAddress; private byte[] _backingBuffer; private int _bufferAlignment; @@ -42,7 +42,7 @@ namespace Microsoft.Net.Http.Server internal NativeRequestContext(AsyncAcceptContext result) { _acceptResult = result; - UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* requestBlob = Allocate(0); + HttpApi.HTTP_REQUEST* requestBlob = Allocate(0); if (requestBlob == null) { GC.SuppressFinalize(this); @@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server } } - internal UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* RequestBlob + internal HttpApi.HTTP_REQUEST* RequestBlob { get { @@ -98,7 +98,7 @@ namespace Microsoft.Net.Http.Server { get { - UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* blob = _memoryBlob; + HttpApi.HTTP_REQUEST* blob = _memoryBlob; return blob == null ? _originalBlobAddress : (IntPtr)blob; } } @@ -138,7 +138,7 @@ namespace Microsoft.Net.Http.Server } } - private void SetBlob(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* requestBlob) + private void SetBlob(HttpApi.HTTP_REQUEST* requestBlob) { Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::Dispose()|SetBlob() called after ReleasePins()."); if (requestBlob == null) @@ -170,7 +170,7 @@ namespace Microsoft.Net.Http.Server _backingBuffer = new byte[size + AlignmentPadding]; } - private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size) + private HttpApi.HTTP_REQUEST* Allocate(uint size) { // We can't reuse overlapped objects if (_nativeOverlapped != null) @@ -191,7 +191,7 @@ namespace Microsoft.Net.Http.Server var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07); - return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment); + return (HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment); } internal void Reset(ulong requestId, uint size) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index f812891410..0d46ac9f77 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -68,7 +68,7 @@ namespace Microsoft.Net.Http.Server RawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); } - UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl; + HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl; if (cookedUrl.pHost != null && cookedUrl.HostLength > 0) { // TODO: Unused @@ -119,10 +119,10 @@ namespace Microsoft.Net.Http.Server } KnownMethod = memoryBlob.RequestBlob->Verb; - Method = UnsafeNclNativeMethods.HttpApi.GetVerb(memoryBlob.RequestBlob); + Method = HttpApi.GetVerb(memoryBlob.RequestBlob); Headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); - var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; + var requestV2 = (HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; User = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount); GetTlsTokenBindingInfo(); @@ -207,9 +207,9 @@ namespace Microsoft.Net.Http.Server public HeaderCollection Headers { get; } - internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB KnownMethod { get; } + internal HttpApi.HTTP_VERB KnownMethod { get; } - public bool IsHeadMethod => KnownMethod == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD; + public bool IsHeadMethod => KnownMethod == HttpApi.HTTP_VERB.HttpVerbHEAD; public string Method { get; } @@ -251,7 +251,7 @@ namespace Microsoft.Net.Http.Server { if (_remoteEndPoint == null) { - _remoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress); + _remoteEndPoint = HttpApi.GetRemoteEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress); } return _remoteEndPoint; @@ -264,7 +264,7 @@ namespace Microsoft.Net.Http.Server { if (_localEndPoint == null) { - _localEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress); + _localEndPoint = HttpApi.GetLocalEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress); } return _localEndPoint; @@ -349,13 +349,13 @@ namespace Microsoft.Net.Http.Server // Value: "iexplore.exe"=dword:00000001 private unsafe void GetTlsTokenBindingInfo() { - var nativeRequest = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)_nativeRequestContext.RequestBlob; + var nativeRequest = (HttpApi.HTTP_REQUEST_V2*)_nativeRequestContext.RequestBlob; for (int i = 0; i < nativeRequest->RequestInfoCount; i++) { var pThisInfo = &nativeRequest->pRequestInfo[i]; - if (pThisInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeSslTokenBinding) + if (pThisInfo->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeSslTokenBinding) { - var pTokenBindingInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO*)pThisInfo->pInfo; + var pTokenBindingInfo = (HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO*)pThisInfo->pInfo; _providedTokenBindingId = TokenBindingUtil.GetProvidedTokenIdFromBindingInfo(pTokenBindingInfo, out _referredTokenBindingId); } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 6f588fae19..5ad6bbf78d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -136,7 +136,7 @@ namespace Microsoft.Net.Http.Server return false; } - if (Request.KnownMethod != UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbGET) + if (Request.KnownMethod != HttpApi.HTTP_VERB.HttpVerbGET) { return false; } @@ -186,7 +186,7 @@ namespace Microsoft.Net.Http.Server throw new InvalidOperationException("This request is not a valid upgrade request."); } - if (Request.KnownMethod != UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbGET) + if (Request.KnownMethod != HttpApi.HTTP_VERB.HttpVerbGET) { throw new InvalidOperationException("This request is not a valid upgrade request; invalid verb: " + Request.Method); } @@ -352,7 +352,7 @@ namespace Microsoft.Net.Http.Server { try { - var statusCode = UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(Server.RequestQueue.Handle, + var statusCode = HttpApi.HttpCancelHttpRequest(Server.RequestQueue.Handle, Request.RequestId, IntPtr.Zero); // Either the connection has already dropped, or the last write is in progress. diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs index 1680f723d5..a1c526d68b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs @@ -85,13 +85,13 @@ namespace Microsoft.Net.Http.Server private string GetKnownHeader(HttpSysRequestHeader header) { - return UnsafeNclNativeMethods.HttpApi.GetKnownHeader(_requestMemoryBlob.RequestBuffer, + return HttpApi.GetKnownHeader(_requestMemoryBlob.RequestBuffer, _requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress, (int)header); } private void GetUnknownHeaders(IDictionary extra) { - UnsafeNclNativeMethods.HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer, + HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer, _requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 460471838a..16324aa487 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -154,7 +154,7 @@ namespace Microsoft.Net.Http.Server if (_dataChunkIndex != -1) { - dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, + dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); } @@ -179,7 +179,7 @@ namespace Microsoft.Net.Http.Server uint flags = 0; statusCode = - UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( + HttpApi.HttpReceiveRequestEntityBody( RequestQueueHandle, RequestId, flags, @@ -232,7 +232,7 @@ namespace Microsoft.Net.Http.Server uint dataRead = 0; if (_dataChunkIndex != -1) { - dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, + dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); if (_dataChunkIndex != -1 && dataRead == size) @@ -262,7 +262,7 @@ namespace Microsoft.Net.Http.Server uint flags = 0; statusCode = - UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( + HttpApi.HttpReceiveRequestEntityBody( RequestQueueHandle, RequestId, flags, @@ -350,7 +350,7 @@ namespace Microsoft.Net.Http.Server uint dataRead = 0; if (_dataChunkIndex != -1) { - dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, + dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); if (_dataChunkIndex != -1 && dataRead == size) { @@ -386,7 +386,7 @@ namespace Microsoft.Net.Http.Server uint flags = 0; statusCode = - UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody( + HttpApi.HttpReceiveRequestEntityBody( RequestQueueHandle, RequestId, flags, diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 119f87d949..1b3c94883a 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -406,9 +406,9 @@ namespace Microsoft.Net.Http.Server _requestContext.Abort(); } - private UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS ComputeLeftToWrite(bool endOfRequest = false) + private HttpApi.HTTP_FLAGS ComputeLeftToWrite(bool endOfRequest = false) { - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; + HttpApi.HTTP_FLAGS flags = HttpApi.HTTP_FLAGS.NONE; if (!_requestContext.Response.ComputedHeaders) { flags = _requestContext.Response.ComputeHeaders(endOfRequest, _buffer.TotalBytes); @@ -565,7 +565,7 @@ namespace Microsoft.Net.Http.Server internal unsafe Task SendFileAsyncCore(string fileName, long offset, long? count, CancellationToken cancellationToken) { _requestContext.Response.Start(); - UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); + HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); if (count == 0 && _leftToWrite != 0) { return Helpers.CompletedTask(); diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index 94f3625fc0..8c7155f710 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -35,7 +35,7 @@ namespace Microsoft.Net.Http.Server public sealed class TimeoutManager { private static readonly int TimeoutLimitSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private WebListener _server; private int[] _timeouts; @@ -69,11 +69,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody); + return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.EntityBody); } set { - SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value); + SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value); } } @@ -92,11 +92,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody); + return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody); } set { - SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value); + SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value); } } @@ -110,11 +110,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue); + return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue); } set { - SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value); + SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value); } } @@ -129,11 +129,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection); + return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection); } set { - SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value); + SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value); } } @@ -149,11 +149,11 @@ namespace Microsoft.Net.Http.Server { get { - return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait); + return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait); } set { - SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value); + SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value); } } @@ -189,13 +189,13 @@ namespace Microsoft.Net.Http.Server #region Helpers - private TimeSpan GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type) + private TimeSpan GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE type) { // Since we maintain local state, GET is local. return new TimeSpan(0, 0, (int)_timeouts[(int)type]); } - private void SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value) + private void SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value) { // All timeouts are defined as USHORT in native layer (except MinSendRate, which is ULONG). Make sure that // timeout value is within range. @@ -217,25 +217,25 @@ namespace Microsoft.Net.Http.Server private unsafe void SetServerTimeouts(int[] timeouts, uint minSendBytesPerSecond) { - var timeoutinfo = new UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO(); + var timeoutinfo = new HttpApi.HTTP_TIMEOUT_LIMIT_INFO(); - timeoutinfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + timeoutinfo.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; timeoutinfo.DrainEntityBody = - (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody]; + (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody]; timeoutinfo.EntityBody = - (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody]; + (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.EntityBody]; timeoutinfo.RequestQueue = - (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue]; + (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue]; timeoutinfo.IdleConnection = - (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection]; + (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection]; timeoutinfo.HeaderWait = - (ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait]; + (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait]; timeoutinfo.MinSendRate = minSendBytesPerSecond; var infoptr = new IntPtr(&timeoutinfo); _server.UrlGroup.SetProperty( - UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty, + HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty, infoptr, (uint)TimeoutLimitSize); } diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 960373d82e..be2e30dbb8 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -81,15 +81,15 @@ namespace Microsoft.Net.Http.Server public WebListener(ILoggerFactory factory) { - if (!UnsafeNclNativeMethods.HttpApi.Supported) + if (!HttpApi.Supported) { throw new PlatformNotSupportedException(); } _logger = LogHelper.CreateLogger(factory, typeof(WebListener)); - Debug.Assert(UnsafeNclNativeMethods.HttpApi.ApiVersion == - UnsafeNclNativeMethods.HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version"); + Debug.Assert(HttpApi.ApiVersion == + HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version"); _state = State.Stopped; _internalLock = new object(); @@ -399,7 +399,7 @@ namespace Microsoft.Net.Http.Server internal unsafe bool ValidateAuth(NativeRequestContext requestMemory) { - var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob; + var requestV2 = (HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob; if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) { SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, @@ -411,8 +411,8 @@ namespace Microsoft.Net.Http.Server private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode, IList authChallenges) { - UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2(); - httpResponse.Response_V1.Version = new UnsafeNclNativeMethods.HttpApi.HTTP_VERSION(); + HttpApi.HTTP_RESPONSE_V2 httpResponse = new HttpApi.HTTP_RESPONSE_V2(); + httpResponse.Response_V1.Version = new HttpApi.HTTP_VERSION(); httpResponse.Response_V1.Version.MajorVersion = (ushort)1; httpResponse.Response_V1.Version.MinorVersion = (ushort)1; @@ -425,25 +425,25 @@ namespace Microsoft.Net.Http.Server { pinnedHeaders = new List(); - UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; - knownHeaderInfo = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[1]; + HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; + knownHeaderInfo = new HttpApi.HTTP_RESPONSE_INFO[1]; gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - httpResponse.pResponseInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); + httpResponse.pResponseInfo = (HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); - knownHeaderInfo[httpResponse.ResponseInfoCount].Type = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; + knownHeaderInfo[httpResponse.ResponseInfoCount].Type = HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[httpResponse.ResponseInfoCount].Length = - (uint)Marshal.SizeOf(); + (uint)Marshal.SizeOf(); - UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); + HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); - header.HeaderId = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderWwwAuthenticate; - header.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // The docs say this is for www-auth only. + header.HeaderId = HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderWwwAuthenticate; + header.Flags = HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // The docs say this is for www-auth only. - UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER[authChallenges.Count]; + HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApi.HTTP_KNOWN_HEADER[authChallenges.Count]; gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - header.KnownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + header.KnownHeaders = (HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); for (int headerValueIndex = 0; headerValueIndex < authChallenges.Count; headerValueIndex++) { @@ -460,7 +460,7 @@ namespace Microsoft.Net.Http.Server // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - knownHeaderInfo[0].pInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); + knownHeaderInfo[0].pInfo = (HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); httpResponse.ResponseInfoCount = 1; } @@ -483,7 +483,7 @@ namespace Microsoft.Net.Http.Server httpResponse.Response_V1.Headers.UnknownHeaderCount = 0; statusCode = - UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse( + HttpApi.HttpSendHttpResponse( _requestQueue.Handle, requestId, 0, @@ -499,7 +499,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { // if we fail to send a 401 something's seriously wrong, abort the request - UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(_requestQueue.Handle, requestId, IntPtr.Zero); + HttpApi.HttpCancelHttpRequest(_requestQueue.Handle, requestId, IntPtr.Zero); } } finally diff --git a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs b/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs deleted file mode 100644 index 89ded72c3a..0000000000 --- a/src/Microsoft.Net.Http.Server/fx/System/Diagnostics/TraceEventType.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -#if NETSTANDARD1_3 - -using System; -using System.ComponentModel; - -namespace System.Diagnostics -{ - internal enum TraceEventType - { - Critical = 0x01, - Error = 0x02, - Warning = 0x04, - Information = 0x08, - Verbose = 0x10, - - [EditorBrowsable(EditorBrowsableState.Advanced)] - Start = 0x0100, - [EditorBrowsable(EditorBrowsableState.Advanced)] - Stop = 0x0200, - [EditorBrowsable(EditorBrowsableState.Advanced)] - Suspend = 0x0400, - [EditorBrowsable(EditorBrowsableState.Advanced)] - Resume = 0x0800, - [EditorBrowsable(EditorBrowsableState.Advanced)] - Transfer = 0x1000, - } -} - -#endif diff --git a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs b/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs deleted file mode 100644 index 989211c70c..0000000000 --- a/src/Microsoft.Net.Http.Server/fx/System/ExternDll.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -#if NETSTANDARD1_3 - -namespace System -{ - internal static class ExternDll - { - public const string api_ms_win_core_localization_LIB = "api-ms-win-core-localization-l2-1-0.dll"; - } -} -#endif diff --git a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs b/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs deleted file mode 100644 index 807bdd2a60..0000000000 --- a/src/Microsoft.Net.Http.Server/fx/System/Runtime/InteropServices/ExternalException.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ==++== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ==--== -/*============================================================================= -** -** Class: ExternalException -** -** -** Purpose: Exception base class for all errors from Interop or Structured -** Exception Handling code. -** -** -=============================================================================*/ - -#if NETSTANDARD1_3 - -namespace System.Runtime.InteropServices -{ - using System; - using System.Globalization; - - // Base exception for COM Interop errors &; Structured Exception Handler - // exceptions. - // - internal class ExternalException : Exception - { - public ExternalException() - { - SetErrorCode(__HResults.E_FAIL); - } - - public ExternalException(String message) - : base(message) - { - SetErrorCode(__HResults.E_FAIL); - } - - public ExternalException(String message, Exception inner) - : base(message, inner) - { - SetErrorCode(__HResults.E_FAIL); - } - - public ExternalException(String message, int errorCode) - : base(message) - { - SetErrorCode(errorCode); - } - - private void SetErrorCode(int errorCode) - { - HResult = ErrorCode; - } - - private static class __HResults - { - internal const int E_FAIL = unchecked((int)0x80004005); - } - - public virtual int ErrorCode - { - get - { - return HResult; - } - } - - public override String ToString() - { - String message = Message; - String s; - String _className = GetType().ToString(); - s = _className + " (0x" + HResult.ToString("X8", CultureInfo.InvariantCulture) + ")"; - - if (!(String.IsNullOrEmpty(message))) - { - s = s + ": " + message; - } - - Exception _innerException = InnerException; - - if (_innerException != null) - { - s = s + " ---> " + _innerException.ToString(); - } - - - if (StackTrace != null) - s += Environment.NewLine + StackTrace; - - return s; - } - } -} - -#endif diff --git a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs deleted file mode 100644 index 27a17a745c..0000000000 --- a/src/Microsoft.Net.Http.Server/fx/System/SafeNativeMethods.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -#if NETSTANDARD1_3 -using System.Runtime.InteropServices; -using System.Text; - -namespace System -{ - internal static class SafeNativeMethods - { - public const int - FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100, - FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200, - FORMAT_MESSAGE_FROM_STRING = 0x00000400, - FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000, - FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; - - [DllImport(ExternDll.api_ms_win_core_localization_LIB, CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true, BestFitMapping = true)] - public static unsafe extern int FormatMessage(int dwFlags, IntPtr lpSource_mustBeNull, uint dwMessageId, - int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr[] arguments); - } -} -#endif From 0fc5dc1820009500ffbecefc1d6915774a64c03d Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 9 Aug 2016 13:41:31 -0700 Subject: [PATCH 370/597] #160 Rename UrlPrefix.Whole to FullPrefix. Make IsHeadMethod internal --- .../RequestProcessing/Request.cs | 2 +- src/Microsoft.Net.Http.Server/UrlPrefix.cs | 10 +++++----- src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs | 8 ++++---- .../ResponseCachingTests.cs | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 0d46ac9f77..481f600692 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -209,7 +209,7 @@ namespace Microsoft.Net.Http.Server internal HttpApi.HTTP_VERB KnownMethod { get; } - public bool IsHeadMethod => KnownMethod == HttpApi.HTTP_VERB.HttpVerbHEAD; + internal bool IsHeadMethod => KnownMethod == HttpApi.HTTP_VERB.HttpVerbHEAD; public string Method { get; } diff --git a/src/Microsoft.Net.Http.Server/UrlPrefix.cs b/src/Microsoft.Net.Http.Server/UrlPrefix.cs index d09b77d08f..4c23f598d5 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefix.cs @@ -36,7 +36,7 @@ namespace Microsoft.Net.Http.Server Port = port; PortValue = portValue; Path = path; - Whole = string.Format(CultureInfo.InvariantCulture, "{0}://{1}:{2}{3}", Scheme, Host, Port, Path); + FullPrefix = string.Format(CultureInfo.InvariantCulture, "{0}://{1}:{2}{3}", Scheme, Host, Port, Path); } /// @@ -169,21 +169,21 @@ namespace Microsoft.Net.Http.Server public string Port { get; private set; } public int PortValue { get; private set; } public string Path { get; private set; } - public string Whole { get; private set; } + public string FullPrefix { get; private set; } public override bool Equals(object obj) { - return string.Equals(Whole, Convert.ToString(obj), StringComparison.OrdinalIgnoreCase); + return string.Equals(FullPrefix, Convert.ToString(obj), StringComparison.OrdinalIgnoreCase); } public override int GetHashCode() { - return StringComparer.OrdinalIgnoreCase.GetHashCode(Whole); + return StringComparer.OrdinalIgnoreCase.GetHashCode(FullPrefix); } public override string ToString() { - return Whole; + return FullPrefix; } } } diff --git a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs index fb64fa6561..b8f417ca14 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs @@ -49,7 +49,7 @@ namespace Microsoft.Net.Http.Server var id = _nextId++; if (_webListener.IsListening) { - _webListener.UrlGroup.RegisterPrefix(item.Whole, id); + _webListener.UrlGroup.RegisterPrefix(item.FullPrefix, id); } _prefixes.Add(id, item); } @@ -108,7 +108,7 @@ namespace Microsoft.Net.Http.Server id = pair.Key; if (_webListener.IsListening) { - _webListener.UrlGroup.UnregisterPrefix(pair.Value.Whole); + _webListener.UrlGroup.UnregisterPrefix(pair.Value.FullPrefix); } } } @@ -142,7 +142,7 @@ namespace Microsoft.Net.Http.Server foreach (var pair in _prefixes) { // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. - _webListener.UrlGroup.RegisterPrefix(pair.Value.Whole, pair.Key); + _webListener.UrlGroup.RegisterPrefix(pair.Value.FullPrefix, pair.Key); } } } @@ -155,7 +155,7 @@ namespace Microsoft.Net.Http.Server foreach (var prefix in _prefixes.Values) { // ignore possible failures - _webListener.UrlGroup.UnregisterPrefix(prefix.Whole); + _webListener.UrlGroup.UnregisterPrefix(prefix.FullPrefix); } } } diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index 541a1716e6..ff48f77414 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_JustPublic_NotCached() { var requestCount = 1; From 81192017c90cc5a80961e49ee66251e4d2063851 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 9 Aug 2016 15:17:20 -0700 Subject: [PATCH 371/597] Migrate to dotnet.myget.org feed --- NuGet.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 1707938c61..826a1f9035 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file From fe6ecfde65b6b9a1c8b1a1db077e2fc85654082c Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 3 Aug 2016 15:55:57 -0700 Subject: [PATCH 372/597] #160 Remove response body buffering, fix layering of related features --- .../FeatureContext.cs | 114 ++++++++++--- .../Helpers.cs | 5 +- .../MessagePump.cs | 22 ++- .../ResponseStream.cs | 143 ++++++++++++++++ .../NativeInterop/TokenBindingUtil.cs | 2 +- .../RequestProcessing/BufferBuilder.cs | 50 ------ .../RequestProcessing/Response.cs | 149 ++--------------- .../RequestProcessing/ResponseStream.cs | 156 +++++++----------- .../ResponseStreamAsyncResult.cs | 25 +-- src/Microsoft.Net.Http.Server/WebListener.cs | 8 - .../OpaqueUpgradeTests.cs | 34 ++++ .../ResponseBodyTests.cs | 107 ++++++++++-- .../ResponseSendFileTests.cs | 66 ++++++-- .../ResponseTests.cs | 96 ++++++++++- .../WebSocketTests.cs | 33 ++++ .../ResponseBodyTests.cs | 114 +------------ .../ResponseCachingTests.cs | 1 - .../ResponseSendFileTests.cs | 2 +- 18 files changed, 646 insertions(+), 481 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs delete mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/BufferBuilder.cs diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index df448e2b72..2d9fe77c77 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -16,8 +16,10 @@ // permissions and limitations under the License. using System; +using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Net; using System.Net.WebSockets; using System.Security.Claims; @@ -46,8 +48,6 @@ namespace Microsoft.AspNetCore.Server.WebListener IHttpUpgradeFeature, IHttpRequestIdentifierFeature { - private static Func OnStartDelegate = OnStart; - private RequestContext _requestContext; private IFeatureCollection _features; private bool _enableResponseCaching; @@ -74,13 +74,18 @@ namespace Microsoft.AspNetCore.Server.WebListener private Stream _responseStream; private IHeaderDictionary _responseHeaders; + private List, object>> _onStartingActions = new List, object>>(); + private List, object>> _onCompletedActions = new List, object>>(); + private bool _responseStarted; + private bool _completed; + internal FeatureContext(RequestContext requestContext, bool enableResponseCaching) { _requestContext = requestContext; _features = new FeatureCollection(new StandardFeatureCollection(this)); _authHandler = new AuthenticationHandler(requestContext); _enableResponseCaching = enableResponseCaching; - requestContext.Response.OnStarting(OnStartDelegate, this); + _responseStream = new ResponseStream(requestContext.Response.Body, OnStart); } internal IFeatureCollection Features @@ -346,7 +351,7 @@ namespace Microsoft.AspNetCore.Server.WebListener void IHttpBufferingFeature.DisableResponseBuffering() { - Response.ShouldBuffer = false; + // TODO: What about native buffering? } Stream IHttpResponseFeature.Body @@ -382,12 +387,30 @@ namespace Microsoft.AspNetCore.Server.WebListener void IHttpResponseFeature.OnStarting(Func callback, object state) { - Response.OnStarting(callback, state); + if (callback == null) + { + throw new ArgumentNullException(nameof(callback)); + } + if (_onStartingActions == null) + { + throw new InvalidOperationException("Cannot register new callbacks, the response has already started."); + } + + _onStartingActions.Add(new Tuple, object>(callback, state)); } void IHttpResponseFeature.OnCompleted(Func callback, object state) { - Response.OnCompleted(callback, state); + if (callback == null) + { + throw new ArgumentNullException(nameof(callback)); + } + if (_onCompletedActions == null) + { + throw new InvalidOperationException("Cannot register new callbacks, the response has already completed."); + } + + _onCompletedActions.Add(new Tuple, object>(callback, state)); } string IHttpResponseFeature.ReasonPhrase @@ -402,9 +425,10 @@ namespace Microsoft.AspNetCore.Server.WebListener set { Response.StatusCode = value; } } - Task IHttpSendFileFeature.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) + async Task IHttpSendFileFeature.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) { - return Response.SendFileAsync(path, offset, length, cancellation); + await OnStart(); + await Response.SendFileAsync(path, offset, length, cancellation); } CancellationToken IHttpRequestLifetimeFeature.RequestAborted @@ -430,14 +454,15 @@ namespace Microsoft.AspNetCore.Server.WebListener get { return _requestContext.IsUpgradableRequest; } } - Task IHttpUpgradeFeature.UpgradeAsync() + async Task IHttpUpgradeFeature.UpgradeAsync() { - return _requestContext.UpgradeAsync(); + await OnStart(); + return await _requestContext.UpgradeAsync(); } bool IHttpWebSocketFeature.IsWebSocketRequest => _requestContext.IsWebSocketRequest; - Task IHttpWebSocketFeature.AcceptAsync(WebSocketAcceptContext context) + async Task IHttpWebSocketFeature.AcceptAsync(WebSocketAcceptContext context) { // TODO: Advanced params string subProtocol = null; @@ -445,7 +470,9 @@ namespace Microsoft.AspNetCore.Server.WebListener { subProtocol = context.SubProtocol; } - return _requestContext.AcceptWebSocketAsync(subProtocol); + + await OnStart(); + return await _requestContext.AcceptWebSocketAsync(subProtocol); } ClaimsPrincipal IHttpAuthenticationFeature.User @@ -480,22 +507,42 @@ namespace Microsoft.AspNetCore.Server.WebListener set { _requestId = value; } } - private static Task OnStart(object obj) + internal async Task OnStart() { - var featureContext = (FeatureContext)obj; - - ConsiderEnablingResponseCache(featureContext); - return Task.FromResult(0); + if (_responseStarted) + { + return; + } + _responseStarted = true; + await NotifiyOnStartingAsync(); + ConsiderEnablingResponseCache(); } - private static void ConsiderEnablingResponseCache(FeatureContext featureContext) + private async Task NotifiyOnStartingAsync() { - if (featureContext._enableResponseCaching) + var actions = _onStartingActions; + _onStartingActions = null; + if (actions == null) + { + return; + } + + actions.Reverse(); + // Execute last to first. This mimics a stack unwind. + foreach (var actionPair in actions) + { + await actionPair.Item1(actionPair.Item2); + } + } + + private void ConsiderEnablingResponseCache() + { + if (_enableResponseCaching) { // We don't have to worry too much about what Http.Sys supports, caching is a best-effort feature. // If there's something about the request or response that prevents it from caching then the response // will complete normally without caching. - featureContext._requestContext.Response.CacheTtl = GetCacheTtl(featureContext._requestContext); + _requestContext.Response.CacheTtl = GetCacheTtl(_requestContext); } } @@ -544,5 +591,32 @@ namespace Microsoft.AspNetCore.Server.WebListener return null; } + + internal Task OnCompleted() + { + if (_completed) + { + return Helpers.CompletedTask; + } + _completed = true; + return NotifyOnCompletedAsync(); + } + + private async Task NotifyOnCompletedAsync() + { + var actions = _onCompletedActions; + _onCompletedActions = null; + if (actions == null) + { + return; + } + + actions.Reverse(); + // Execute last to first. This mimics a stack unwind. + foreach (var actionPair in actions) + { + await actionPair.Item1(actionPair.Item2); + } + } } } diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs index f9ff181782..1b7efd9698 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs @@ -28,10 +28,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { internal static class Helpers { - internal static Task CompletedTask() - { - return Task.FromResult(null); - } + internal static Task CompletedTask { get; } = Task.FromResult(0); internal static ConfiguredTaskAwaitable SupressContext(this Task task) { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs index a686dc782e..591b060900 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs @@ -166,26 +166,34 @@ namespace Microsoft.AspNetCore.Server.WebListener } object context = null; + Interlocked.Increment(ref _outstandingRequests); try { - Interlocked.Increment(ref _outstandingRequests); - FeatureContext featureContext = new FeatureContext(requestContext, EnableResponseCaching); + var featureContext = new FeatureContext(requestContext, EnableResponseCaching); context = _application.CreateContext(featureContext.Features); - await _application.ProcessRequestAsync(context).SupressContext(); - requestContext.Dispose(); - _application.DisposeContext(context, null); + try + { + await _application.ProcessRequestAsync(context).SupressContext(); + await featureContext.OnStart(); + requestContext.Dispose(); + _application.DisposeContext(context, null); + } + finally + { + await featureContext.OnCompleted(); + } } catch (Exception ex) { LogHelper.LogException(_logger, "ProcessRequestAsync", ex); - if (requestContext.Response.HasStartedSending) + if (requestContext.Response.HasStarted) { requestContext.Abort(); } else { // We haven't sent a response yet, try to send a 500 Internal Server Error - requestContext.Response.Reset(); + requestContext.Response.Headers.Clear(); SetFatalResponse(requestContext, 500); } _application.DisposeContext(context, ex); diff --git a/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs b/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs new file mode 100644 index 0000000000..d641124c42 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Server.WebListener +{ + internal class ResponseStream : Stream + { + private readonly Stream _innerStream; + private readonly Func _onStart; + + internal ResponseStream(Stream innerStream, Func onStart) + { + _innerStream = innerStream; + _onStart = onStart; + } + + public override bool CanRead => _innerStream.CanRead; + + public override bool CanSeek => _innerStream.CanSeek; + + public override bool CanWrite => _innerStream.CanWrite; + + public override long Length => _innerStream.Length; + + public override long Position + { + get { return _innerStream.Position; } + set { _innerStream.Position = value; } + } + + public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin); + + public override void SetLength(long value) => _innerStream.SetLength(value); + + public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count); + +#if !NETSTANDARD1_3 + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return _innerStream.BeginRead(buffer, offset, count, callback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + return _innerStream.EndRead(asyncResult); + } +#endif + public override void Flush() + { + _onStart().GetAwaiter().GetResult(); + _innerStream.Flush(); + } + + public override async Task FlushAsync(CancellationToken cancellationToken) + { + await _onStart(); + await _innerStream.FlushAsync(cancellationToken); + } + + public override void Write(byte[] buffer, int offset, int count) + { + _onStart().GetAwaiter().GetResult(); + _innerStream.Write(buffer, offset, count); + } + + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + await _onStart(); + await _innerStream.WriteAsync(buffer, offset, count, cancellationToken); + } +#if NETSTANDARD1_3 + public IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) +#else + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) +#endif + { + return ToIAsyncResult(WriteAsync(buffer, offset, count), callback, state); + } +#if NETSTANDARD1_3 + public void EndWrite(IAsyncResult asyncResult) +#else + public override void EndWrite(IAsyncResult asyncResult) +#endif + { + if (asyncResult == null) + { + throw new ArgumentNullException(nameof(asyncResult)); + } + ((Task)asyncResult).GetAwaiter().GetResult(); + } + + private static IAsyncResult ToIAsyncResult(Task task, AsyncCallback callback, object state) + { + var tcs = new TaskCompletionSource(state); + task.ContinueWith(t => + { + if (t.IsFaulted) + { + tcs.TrySetException(t.Exception.InnerExceptions); + } + else if (t.IsCanceled) + { + tcs.TrySetCanceled(); + } + else + { + tcs.TrySetResult(0); + } + + if (callback != null) + { + callback(tcs.Task); + } + }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); + return tcs.Task; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs index eeeb1ed395..2b6fe417be 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs @@ -30,7 +30,7 @@ namespace Microsoft.Net.Http.Server private static byte[] ExtractIdentifierBlob(TOKENBINDING_RESULT_DATA* pTokenBindingResultData) { // Per http://tools.ietf.org/html/draft-ietf-tokbind-protocol-00, Sec. 4, - // the identifer is a tuple which contains (token binding type, hash algorithm + // the identifier is a tuple which contains (token binding type, hash algorithm // signature algorithm, key data). We'll strip off the token binding type and // return the remainder (starting with the hash algorithm) as an opaque blob. byte[] retVal = new byte[checked(pTokenBindingResultData->identifierSize - 1)]; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/BufferBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/BufferBuilder.cs deleted file mode 100644 index 5cb08d271d..0000000000 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/BufferBuilder.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.Net.Http.Server -{ - internal class BufferBuilder - { - private List> _buffers = new List>(); - - internal IEnumerable> Buffers - { - get { return _buffers; } - } - - internal int BufferCount - { - get { return _buffers.Count; } - } - - internal int TotalBytes { get; private set; } - - internal void Add(ArraySegment data) - { - _buffers.Add(data); - TotalBytes += data.Count; - } - - public void CopyAndAdd(ArraySegment data) - { - if (data.Count > 0) - { - var temp = new byte[data.Count]; - Buffer.BlockCopy(data.Array, data.Offset, temp, 0, data.Count); - _buffers.Add(new ArraySegment(temp)); - TotalBytes += data.Count; - } - } - - public void Clear() - { - _buffers.Clear(); - TotalBytes = 0; - } - } -} diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 1203105e3f..023d4edab8 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -26,11 +26,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; -using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; @@ -46,25 +44,12 @@ namespace Microsoft.Net.Http.Server private long _expectedBodyLength; private BoundaryType _boundaryType; private HttpApi.HTTP_RESPONSE_V2 _nativeResponse; - private IList, object>> _onStartingActions; - private IList, object>> _onCompletedActions; - - private bool _bufferingEnabled; internal Response(RequestContext requestContext) { // TODO: Verbose log RequestContext = requestContext; Headers = new HeaderCollection(); - Reset(); - } - - public void Reset() - { - if (_responseState >= ResponseState.StartedSending) - { - throw new InvalidOperationException("The response has already been sent. Request Aborted."); - } // We haven't started yet, or we're just buffered, we can clear any data, headers, and state so // that we can start over (e.g. to write an error message). _nativeResponse = new HttpApi.HTTP_RESPONSE_V2(); @@ -76,9 +61,6 @@ namespace Microsoft.Net.Http.Server _nativeResponse.Response_V1.Version.MajorVersion = 1; _nativeResponse.Response_V1.Version.MinorVersion = 1; _responseState = ResponseState.Created; - _onStartingActions = new List, object>>(); - _onCompletedActions = new List, object>>(); - _bufferingEnabled = RequestContext.Server.BufferResponses; _expectedBodyLength = 0; _nativeStream = null; _cacheTtl = null; @@ -88,9 +70,8 @@ namespace Microsoft.Net.Http.Server private enum ResponseState { Created, - Started, ComputedHeaders, - StartedSending, + Started, Closed, } @@ -124,16 +105,6 @@ namespace Microsoft.Net.Http.Server } } - public bool ShouldBuffer - { - get { return _bufferingEnabled; } - set - { - CheckResponseStarted(); - _bufferingEnabled = value; - } - } - public Stream Body { get @@ -279,8 +250,6 @@ namespace Microsoft.Net.Http.Server { return; } - Start(); - NotifyOnResponseCompleted(); // TODO: Verbose log EnsureResponseStream(); _nativeStream.Dispose(); @@ -292,11 +261,14 @@ namespace Microsoft.Net.Http.Server get { return _boundaryType; } } + internal bool HasComputedHeaders + { + get { return _responseState >= ResponseState.ComputedHeaders; } + } + /// /// Indicates if the response status, reason, and headers are prepared to send and can - /// no longer be modified. This is caused by the first write to the response body. However, - /// the response may not have been flushed to the network yet if the body is buffered. - /// See HasStartedSending. + /// no longer be modified. This is caused by the first write or flush to the response body. /// public bool HasStarted { @@ -311,19 +283,6 @@ namespace Microsoft.Net.Http.Server } } - internal bool ComputedHeaders - { - get { return _responseState >= ResponseState.ComputedHeaders; } - } - - /// - /// Indicates the initial response has been flushed to the network and can no longer be modified or Reset. - /// - public bool HasStartedSending - { - get { return _responseState >= ResponseState.StartedSending; } - } - private void EnsureResponseStream() { if (_nativeStream == null) @@ -367,9 +326,9 @@ namespace Microsoft.Net.Http.Server HttpApi.HTTP_FLAGS flags, bool isOpaqueUpgrade) { - Debug.Assert(!HasStartedSending, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); + Debug.Assert(!HasStarted, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); - _responseState = ResponseState.StartedSending; + _responseState = ResponseState.Started; var reasonPhrase = GetReasonPhrase(StatusCode); /* @@ -448,21 +407,8 @@ namespace Microsoft.Net.Http.Server return statusCode; } - internal void Start() + internal HttpApi.HTTP_FLAGS ComputeHeaders(bool endOfRequest = false) { - if (!HasStarted) - { - // Notify that this is absolutely the last chance to make changes. - NotifyOnSendingHeaders(); - Headers.IsReadOnly = true; // Prohibit further modifications. - _responseState = ResponseState.Started; - } - } - - internal HttpApi.HTTP_FLAGS ComputeHeaders(bool endOfRequest = false, int bufferedBytes = 0) - { - Headers.IsReadOnly = false; // Temporarily allow modification. - // 401 if (StatusCode == (ushort)HttpStatusCode.Unauthorized) { @@ -470,7 +416,7 @@ namespace Microsoft.Net.Http.Server } var flags = HttpApi.HTTP_FLAGS.NONE; - Debug.Assert(!ComputedHeaders, "HttpListenerResponse::ComputeHeaders()|ComputedHeaders is true."); + Debug.Assert(!HasComputedHeaders, nameof(HasComputedHeaders) + " is true."); _responseState = ResponseState.ComputedHeaders; // Gather everything from the request that affects the response: @@ -511,16 +457,12 @@ namespace Microsoft.Net.Http.Server } else if (endOfRequest && !(isHeadRequest && statusCanHaveBody)) // HEAD requests should always end without a body. Assume a GET response would have a body. { - if (bufferedBytes > 0) - { - Headers[HttpKnownHeaderNames.ContentLength] = bufferedBytes.ToString(CultureInfo.InvariantCulture); - } - else if (statusCanHaveBody) + if (statusCanHaveBody) { Headers[HttpKnownHeaderNames.ContentLength] = Constants.Zero; } _boundaryType = BoundaryType.ContentLength; - _expectedBodyLength = bufferedBytes; + _expectedBodyLength = 0; } else if (keepConnectionAlive && requestVersion == Constants.V1_1) { @@ -726,8 +668,6 @@ namespace Microsoft.Net.Http.Server // Subset of ComputeHeaders internal void SendOpaqueUpgrade() { - // Notify that this is absolutely the last chance to make changes. - Start(); _boundaryType = BoundaryType.Close; // TODO: Send headers async? @@ -765,70 +705,7 @@ namespace Microsoft.Net.Http.Server internal void SwitchToOpaqueMode() { EnsureResponseStream(); - _bufferingEnabled = false; _nativeStream.SwitchToOpaqueMode(); } - - public void OnStarting(Func callback, object state) - { - var actions = _onStartingActions; - if (actions == null) - { - throw new InvalidOperationException("Response already started"); - } - - actions.Add(new Tuple, object>(callback, state)); - } - - public void OnCompleted(Func callback, object state) - { - var actions = _onCompletedActions; - if (actions == null) - { - throw new InvalidOperationException("Response already completed"); - } - - actions.Add(new Tuple, object>(callback, state)); - } - - private void NotifyOnSendingHeaders() - { - var actions = Interlocked.Exchange(ref _onStartingActions, null); - if (actions == null) - { - // Something threw the first time, do not try again. - return; - } - - // Execute last to first. This mimics a stack unwind. - foreach (var actionPair in actions.Reverse()) - { - actionPair.Item1(actionPair.Item2); - } - } - - private void NotifyOnResponseCompleted() - { - var actions = Interlocked.Exchange(ref _onCompletedActions, null); - if (actions == null) - { - // Something threw the first time, do not try again. - return; - } - - foreach (var actionPair in actions) - { - try - { - actionPair.Item1(actionPair.Item2); - } - catch (Exception ex) - { - RequestContext.Logger.LogWarning( - String.Format(Resources.Warning_ExceptionInOnResponseCompletedAction, nameof(OnCompleted)), - ex); - } - } - } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 1b3c94883a..04e8f16e64 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -23,8 +23,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Threading; @@ -36,13 +36,10 @@ namespace Microsoft.Net.Http.Server { internal class ResponseStream : Stream { - private const int MaxBufferSize = 4 * 1024; - private RequestContext _requestContext; private long _leftToWrite = long.MinValue; private bool _closed; private bool _inOpaqueMode; - private BufferBuilder _buffer = new BufferBuilder(); // The last write needs special handling to cancel. private ResponseStreamAsyncResult _lastWrite; @@ -117,18 +114,20 @@ namespace Microsoft.Net.Http.Server FlushInternal(endOfRequest: false); } - private unsafe void FlushInternal(bool endOfRequest) + // We never expect endOfRequest and data at the same time + private unsafe void FlushInternal(bool endOfRequest, ArraySegment data = new ArraySegment()) { - bool startedSending = _requestContext.Response.HasStartedSending; - var byteCount = _buffer.TotalBytes; - if (byteCount == 0 && startedSending && !endOfRequest) + Debug.Assert(!(endOfRequest && data.Count > 0), "Data is not supported at the end of the request."); + + var started = _requestContext.Response.HasStarted; + if (data.Count == 0 && started && !endOfRequest) { // Empty flush return; } var flags = ComputeLeftToWrite(endOfRequest); - if (!_inOpaqueMode && endOfRequest && _leftToWrite > byteCount) + if (!_inOpaqueMode && endOfRequest && _leftToWrite > data.Count) { _requestContext.Abort(); // This is logged rather than thrown because it is too late for an exception to be visible in user code. @@ -140,18 +139,18 @@ namespace Microsoft.Net.Http.Server { flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } - else if (!endOfRequest && _leftToWrite != byteCount) + else if (!endOfRequest && _leftToWrite != data.Count) { flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; } - UpdateWritenCount((uint)byteCount); + UpdateWritenCount((uint)data.Count); uint statusCode = 0; HttpApi.HTTP_DATA_CHUNK[] dataChunks; - var pinnedBuffers = PinDataBuffers(endOfRequest, out dataChunks); + var pinnedBuffers = PinDataBuffers(endOfRequest, data, out dataChunks); try { - if (!startedSending) + if (!started) { statusCode = _requestContext.Response.SendHeaders(dataChunks, null, flags, false); } @@ -181,7 +180,6 @@ namespace Microsoft.Net.Http.Server finally { FreeDataBuffers(pinnedBuffers); - _buffer.Clear(); } if (statusCode != ErrorCodes.ERROR_SUCCESS && statusCode != ErrorCodes.ERROR_HANDLE_EOF @@ -195,27 +193,27 @@ namespace Microsoft.Net.Http.Server } } - private List PinDataBuffers(bool endOfRequest, out HttpApi.HTTP_DATA_CHUNK[] dataChunks) + private List PinDataBuffers(bool endOfRequest, ArraySegment data, out HttpApi.HTTP_DATA_CHUNK[] dataChunks) { var pins = new List(); var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; var currentChunk = 0; // Figure out how many data chunks - if (chunked && _buffer.TotalBytes == 0 && endOfRequest) + if (chunked && data.Count == 0 && endOfRequest) { dataChunks = new HttpApi.HTTP_DATA_CHUNK[1]; SetDataChunk(dataChunks, ref currentChunk, pins, new ArraySegment(Helpers.ChunkTerminator)); return pins; } - else if (_buffer.TotalBytes == 0) + else if (data.Count == 0) { // No data dataChunks = new HttpApi.HTTP_DATA_CHUNK[0]; return pins; } - var chunkCount = _buffer.BufferCount; + var chunkCount = 1; if (chunked) { // Chunk framing @@ -231,14 +229,11 @@ namespace Microsoft.Net.Http.Server if (chunked) { - var chunkHeaderBuffer = Helpers.GetChunkHeader(_buffer.TotalBytes); + var chunkHeaderBuffer = Helpers.GetChunkHeader(data.Count); SetDataChunk(dataChunks, ref currentChunk, pins, chunkHeaderBuffer); } - foreach (var buffer in _buffer.Buffers) - { - SetDataChunk(dataChunks, ref currentChunk, pins, buffer); - } + SetDataChunk(dataChunks, ref currentChunk, pins, data); if (chunked) { @@ -274,18 +269,20 @@ namespace Microsoft.Net.Http.Server } } - - // Simpler than Flush because it will never be called at the end of the request from Dispose. - public unsafe override Task FlushAsync(CancellationToken cancellationToken) + public override Task FlushAsync(CancellationToken cancellationToken) { if (_closed) { return Helpers.CompletedTask(); } + return FlushInternalAsync(new ArraySegment(), cancellationToken); + } - bool startedSending = _requestContext.Response.HasStartedSending; - var byteCount = _buffer.TotalBytes; - if (byteCount == 0 && startedSending) + // Simpler than Flush because it will never be called at the end of the request from Dispose. + private unsafe Task FlushInternalAsync(ArraySegment data, CancellationToken cancellationToken) + { + var started = _requestContext.Response.HasStarted; + if (data.Count == 0 && started) { // Empty flush return Helpers.CompletedTask(); @@ -298,19 +295,19 @@ namespace Microsoft.Net.Http.Server } var flags = ComputeLeftToWrite(); - if (_leftToWrite != byteCount) + if (_leftToWrite != data.Count) { flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; } - UpdateWritenCount((uint)byteCount); + UpdateWritenCount((uint)data.Count); uint statusCode = 0; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; - var asyncResult = new ResponseStreamAsyncResult(this, _buffer, chunked, cancellationRegistration); + var asyncResult = new ResponseStreamAsyncResult(this, data, chunked, cancellationRegistration); uint bytesSent = 0; try { - if (!startedSending) + if (!started) { statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); bytesSent = asyncResult.BytesSent; @@ -341,7 +338,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != ErrorCodes.ERROR_SUCCESS && statusCode != ErrorCodes.ERROR_IO_PENDING) { asyncResult.Dispose(); - if (_requestContext.Server.IgnoreWriteExceptions && startedSending) + if (_requestContext.Server.IgnoreWriteExceptions && started) { asyncResult.Complete(); } @@ -408,10 +405,10 @@ namespace Microsoft.Net.Http.Server private HttpApi.HTTP_FLAGS ComputeLeftToWrite(bool endOfRequest = false) { - HttpApi.HTTP_FLAGS flags = HttpApi.HTTP_FLAGS.NONE; - if (!_requestContext.Response.ComputedHeaders) + var flags = HttpApi.HTTP_FLAGS.NONE; + if (!_requestContext.Response.HasComputedHeaders) { - flags = _requestContext.Response.ComputeHeaders(endOfRequest, _buffer.TotalBytes); + flags = _requestContext.Response.ComputeHeaders(endOfRequest); } if (_leftToWrite == long.MinValue) { @@ -437,47 +434,31 @@ namespace Microsoft.Net.Http.Server var data = new ArraySegment(buffer, offset, count); CheckDisposed(); // TODO: Verbose log parameters - // Officially starts the response and fires OnSendingHeaders - _requestContext.Response.Start(); - var currentBytes = _buffer.TotalBytes + data.Count; var contentLength = _requestContext.Response.ContentLength; - if (contentLength.HasValue && !_requestContext.Response.ComputedHeaders && contentLength.Value <= currentBytes) + if (contentLength.HasValue && !_requestContext.Response.HasComputedHeaders && contentLength.Value <= data.Count) { - if (contentLength.Value < currentBytes) + if (contentLength.Value < data.Count) { throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); } - // or the last write in a response that hasn't started yet, flush immideately - _buffer.Add(data); - Flush(); } - // The last write in a response that has already started, flush immidately - else if (_requestContext.Response.ComputedHeaders && _leftToWrite >= 0 && _leftToWrite <= currentBytes) + // The last write in a response that has already started, flush immediately + else if (_requestContext.Response.HasComputedHeaders && _leftToWrite >= 0 && _leftToWrite <= data.Count) { - if (_leftToWrite < currentBytes) + if (_leftToWrite < data.Count) { throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); } - _buffer.Add(data); - Flush(); - } - else if (_requestContext.Response.ShouldBuffer && currentBytes < MaxBufferSize) - { - _buffer.CopyAndAdd(data); - } - else - { - // Append to existing data without a copy, and then flush immidately - _buffer.Add(data); - Flush(); } + + FlushInternal(endOfRequest: false, data: data); } #if NETSTANDARD1_3 - public unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) #else - public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) #endif { return WriteAsync(buffer, offset, count).ToIAsyncResult(callback, state); @@ -490,7 +471,7 @@ namespace Microsoft.Net.Http.Server { if (asyncResult == null) { - throw new ArgumentNullException("asyncResult"); + throw new ArgumentNullException(nameof(asyncResult)); } ((Task)asyncResult).GetAwaiter().GetResult(); } @@ -505,42 +486,25 @@ namespace Microsoft.Net.Http.Server } CheckDisposed(); // TODO: Verbose log parameters - // Officially starts the response and fires OnSendingHeaders - _requestContext.Response.Start(); - var currentBytes = _buffer.TotalBytes + data.Count; var contentLength = _requestContext.Response.ContentLength; - if (contentLength.HasValue && !_requestContext.Response.ComputedHeaders && contentLength.Value <= currentBytes) + if (contentLength.HasValue && !_requestContext.Response.HasComputedHeaders && contentLength.Value <= data.Count) { - if (contentLength.Value < currentBytes) + if (contentLength.Value < data.Count) { throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); } - // The last write in a response that hasn't started yet, flush immideately - _buffer.Add(data); - return FlushAsync(cancellationToken); } - // The last write in a response that has already started, flush immidately - else if (_requestContext.Response.ComputedHeaders && _leftToWrite > 0 && _leftToWrite <= currentBytes) + // The last write in a response that has already started, flush immediately + else if (_requestContext.Response.HasComputedHeaders && _leftToWrite > 0 && _leftToWrite <= data.Count) { - if (_leftToWrite < currentBytes) + if (_leftToWrite < data.Count) { throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); } - _buffer.Add(data); - return FlushAsync(cancellationToken); - } - else if (_requestContext.Response.ShouldBuffer && currentBytes < MaxBufferSize) - { - _buffer.CopyAndAdd(data); - return Helpers.CompletedTask(); - } - else - { - // Append to existing data without a copy, and then flush immidately - _buffer.Add(data); - return FlushAsync(cancellationToken); } + + return FlushInternalAsync(data, cancellationToken); } internal async Task SendFileAsync(string fileName, long offset, long? count, CancellationToken cancellationToken) @@ -552,20 +516,14 @@ namespace Microsoft.Net.Http.Server throw new ArgumentNullException("fileName"); } CheckDisposed(); - if (_buffer.TotalBytes > 0) - { - // SendFileAsync is primarly used for full responses so we don't optimize this partialy buffered scenario. - // In theory we could merge SendFileAsyncCore into FlushAsync[Internal] and send the buffered data in the same call as the file. - await FlushAsync(cancellationToken); - } - // We can't mix await and unsafe so seperate the unsafe code into another method. + + // We can't mix await and unsafe so separate the unsafe code into another method. await SendFileAsyncCore(fileName, offset, count, cancellationToken); } internal unsafe Task SendFileAsyncCore(string fileName, long offset, long? count, CancellationToken cancellationToken) { - _requestContext.Response.Start(); - HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); + var flags = ComputeLeftToWrite(); if (count == 0 && _leftToWrite != 0) { return Helpers.CompletedTask(); @@ -589,7 +547,7 @@ namespace Microsoft.Net.Http.Server uint statusCode; uint bytesSent = 0; - bool startedSending = _requestContext.Response.HasStartedSending; + var started = _requestContext.Response.HasStarted; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, fileName, offset, count, chunked, cancellationRegistration); @@ -612,7 +570,7 @@ namespace Microsoft.Net.Http.Server try { - if (!startedSending) + if (!started) { statusCode = _requestContext.Response.SendHeaders(null, asyncResult, flags, false); bytesSent = asyncResult.BytesSent; @@ -644,7 +602,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) { asyncResult.Dispose(); - if (_requestContext.Server.IgnoreWriteExceptions && startedSending) + if (_requestContext.Server.IgnoreWriteExceptions && started) { asyncResult.Complete(); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 12af57f093..73fa62ff28 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -50,14 +50,14 @@ namespace Microsoft.Net.Http.Server _cancellationRegistration = cancellationRegistration; } - internal ResponseStreamAsyncResult(ResponseStream responseStream, BufferBuilder buffer, bool chunked, + internal ResponseStreamAsyncResult(ResponseStream responseStream, ArraySegment data, bool chunked, CancellationTokenRegistration cancellationRegistration) : this(responseStream, cancellationRegistration) { var boundHandle = _responseStream.RequestContext.Server.RequestQueue.BoundHandle; object[] objectsToPin; - if (buffer.TotalBytes == 0) + if (data.Count == 0) { _dataChunks = null; _overlapped = new SafeNativeOverlapped(boundHandle, @@ -65,7 +65,7 @@ namespace Microsoft.Net.Http.Server return; } - _dataChunks = new HttpApi.HTTP_DATA_CHUNK[buffer.BufferCount + (chunked ? 2 : 0)]; + _dataChunks = new HttpApi.HTTP_DATA_CHUNK[1 + (chunked ? 2 : 0)]; objectsToPin = new object[_dataChunks.Length + 1]; objectsToPin[0] = _dataChunks; var currentChunk = 0; @@ -74,14 +74,11 @@ namespace Microsoft.Net.Http.Server var chunkHeaderBuffer = new ArraySegment(); if (chunked) { - chunkHeaderBuffer = Helpers.GetChunkHeader(buffer.TotalBytes); + chunkHeaderBuffer = Helpers.GetChunkHeader(data.Count); SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, chunkHeaderBuffer); } - foreach (var segment in buffer.Buffers) - { - SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, segment); - } + SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, data); if (chunked) { @@ -98,19 +95,15 @@ namespace Microsoft.Net.Http.Server _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer.Array, chunkHeaderBuffer.Offset); currentChunk++; } - foreach (var segment in buffer.Buffers) - { - _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(segment.Array, segment.Offset); - currentChunk++; - } + + _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(data.Array, data.Offset); + currentChunk++; + if (chunked) { _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(Helpers.CRLF, 0); currentChunk++; } - - // We've captured a reference to all the buffers, clear the buffer so that it can be used to queue overlapped writes. - buffer.Clear(); } internal ResponseStreamAsyncResult(ResponseStream responseStream, string fileName, long offset, diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index be2e30dbb8..5f92de5fae 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -72,8 +72,6 @@ namespace Microsoft.Net.Http.Server // The native request queue private long? _requestQueueLength; - private bool _bufferResponses = true; - public WebListener() : this(null) { @@ -169,12 +167,6 @@ namespace Microsoft.Net.Http.Server get { return _urlPrefixes; } } - public bool BufferResponses - { - get { return _bufferResponses; } - set { _bufferResponses = value; } - } - /// /// Exposes the Http.Sys timeout configurations. These may also be configured in the registry. /// diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index 191208da1e..a311b6b770 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -115,6 +115,40 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] + public async Task OpaqueUpgrade_WithOnStarting_CallbackCalled() + { + var callbackCalled = false; + var waitHandle = new ManualResetEvent(false); + bool? upgraded = null; + string address; + using (Utilities.CreateHttpServer(out address, async httpContext => + { + httpContext.Response.OnStarting(_ => + { + callbackCalled = true; + return Task.FromResult(0); + }, null); + httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets + var opaqueFeature = httpContext.Features.Get(); + Assert.NotNull(opaqueFeature); + Assert.True(opaqueFeature.IsUpgradableRequest); + await opaqueFeature.UpgradeAsync(); + upgraded = true; + waitHandle.Set(); + })) + { + using (Stream stream = await SendOpaqueRequestAsync("GET", address)) + { + Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); + Assert.True(upgraded.HasValue, "Upgraded not set"); + Assert.True(upgraded.Value, "Upgrade failed"); + Assert.True(callbackCalled, "Callback not called"); + } + } + } + [ConditionalTheory] [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] // See HTTP_VERB for known verbs diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 7f6122dccc..9df0c89089 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public class ResponseBodyTests { [Fact] - public async Task ResponseBody_WriteNoHeaders_BuffersAndSetsContentLength() + public async Task ResponseBody_WriteNoHeaders_SetsChunked() { string address; using (Utilities.CreateHttpServer(out address, httpContext => @@ -39,12 +39,12 @@ namespace Microsoft.AspNetCore.Server.WebListener return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; - Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); - Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); } } @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.WebListener await httpContext.Response.Body.FlushAsync(); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; @@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Server.WebListener await stream.WriteAsync(responseBytes, 0, responseBytes.Length); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.WebListener await stream.WriteAsync(new byte[10], 0, 10); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable contentLength; @@ -152,24 +152,26 @@ namespace Microsoft.AspNetCore.Server.WebListener [Fact] public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { + var completed = false; string address; using (Utilities.CreateHttpServer(out address, httpContext => { httpContext.Response.Headers["Content-lenGth"] = " 10 "; httpContext.Response.Body.Write(new byte[5], 0, 5); - httpContext.Response.Body.Write(new byte[6], 0, 6); + Assert.Throws(() => httpContext.Response.Body.Write(new byte[6], 0, 6)); + completed = true; return Task.FromResult(0); })) { - var response = await SendRequestAsync(address); - Assert.Equal(500, (int)response.StatusCode); + await Assert.ThrowsAsync(() => SendRequestAsync(address)); + Assert.True(completed); } } [Fact] public async Task ResponseBody_WriteContentLengthExtraWritten_Throws() { - ManualResetEvent waitHandle = new ManualResetEvent(false); + var waitHandle = new ManualResetEvent(false); bool? appThrew = null; string address; using (Utilities.CreateHttpServer(out address, httpContext => @@ -205,6 +207,89 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + [Fact] + public async Task ResponseBody_Write_TriggersOnStarting() + { + var onStartingCalled = false; + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + httpContext.Response.OnStarting(state => + { + onStartingCalled = true; + Assert.Same(state, httpContext); + return Task.FromResult(0); + }, httpContext); + httpContext.Response.Body.Write(new byte[10], 0, 10); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(onStartingCalled); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + } + } +#if NET451 + [Fact] + public async Task ResponseBody_BeginWrite_TriggersOnStarting() + { + var onStartingCalled = false; + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + httpContext.Response.OnStarting(state => + { + onStartingCalled = true; + Assert.Same(state, httpContext); + return Task.FromResult(0); + }, httpContext); + httpContext.Response.Body.EndWrite(httpContext.Response.Body.BeginWrite(new byte[10], 0, 10, null, null)); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(onStartingCalled); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + } + } +#endif + [Fact] + public async Task ResponseBody_WriteAsync_TriggersOnStarting() + { + var onStartingCalled = false; + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + httpContext.Response.OnStarting(state => + { + onStartingCalled = true; + Assert.Same(state, httpContext); + return Task.FromResult(0); + }, httpContext); + return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(onStartingCalled); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 3c39c77764..7cc9269f12 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.WebListener return Task.FromResult(0); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable ignored; Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Server.WebListener [Fact] public async Task ResponseSendFile_MissingFile_Throws() { - ManualResetEvent waitHandle = new ManualResetEvent(false); + var waitHandle = new ManualResetEvent(false); bool? appThrew = null; string address; using (Utilities.CreateHttpServer(out address, httpContext => @@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -204,7 +204,7 @@ namespace Microsoft.AspNetCore.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -216,30 +216,34 @@ namespace Microsoft.AspNetCore.Server.WebListener [Fact] public async Task ResponseSendFile_OffsetOutOfRange_Throws() { + var completed = false; string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (Utilities.CreateHttpServer(out address, async httpContext => { var sendFile = httpContext.Features.Get(); - return sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); + await sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); + completed = true; })) { - HttpResponseMessage response = await SendRequestAsync(address); - Assert.Equal(500, (int)response.StatusCode); + await Assert.ThrowsAsync(() => SendRequestAsync(address)); + Assert.False(completed); } } [Fact] public async Task ResponseSendFile_CountOutOfRange_Throws() { + var completed = false; string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (Utilities.CreateHttpServer(out address, async httpContext => { var sendFile = httpContext.Features.Get(); - return sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); + await sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); + completed = true; })) { - HttpResponseMessage response = await SendRequestAsync(address); - Assert.Equal(500, (int)response.StatusCode); + await Assert.ThrowsAsync(() => SendRequestAsync(address)); + Assert.False(completed); } } @@ -253,7 +257,7 @@ namespace Microsoft.AspNetCore.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -273,7 +277,7 @@ namespace Microsoft.AspNetCore.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -294,7 +298,7 @@ namespace Microsoft.AspNetCore.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -315,7 +319,7 @@ namespace Microsoft.AspNetCore.Server.WebListener return sendFile.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); })) { - HttpResponseMessage response = await SendRequestAsync(address); + var response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -325,6 +329,34 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + [Fact] + public async Task ResponseSendFile_TriggersOnStarting() + { + var onStartingCalled = false; + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + httpContext.Response.OnStarting(state => + { + onStartingCalled = true; + Assert.Same(state, httpContext); + return Task.FromResult(0); + }, httpContext); + var sendFile = httpContext.Features.Get(); + return sendFile.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + Assert.True(onStartingCalled); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(10, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs index 51aeb4a053..8fcbe69d4e 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -16,6 +16,7 @@ // permissions and limitations under the License. using System; +using System.IO; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -102,7 +103,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } [Fact] - public async Task Response_100_Throws() + public async Task Response_StatusCode100_Throws() { string address; using (Utilities.CreateHttpServer(out address, httpContext => @@ -117,7 +118,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } [Fact] - public async Task Response_0_Throws() + public async Task Response_StatusCode0_Throws() { string address; using (Utilities.CreateHttpServer(out address, httpContext => @@ -131,9 +132,98 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + [Fact] + public async Task Response_Empty_CallsOnStartingAndOnCompleted() + { + var onStartingCalled = false; + var onCompletedCalled = false; + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + httpContext.Response.OnStarting(state => + { + onStartingCalled = true; + Assert.Same(state, httpContext); + return Task.FromResult(0); + }, httpContext); + httpContext.Response.OnCompleted(state => + { + onCompletedCalled = true; + Assert.Same(state, httpContext); + return Task.FromResult(0); + }, httpContext); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(onStartingCalled); + Assert.True(onCompletedCalled); + } + } + + [Fact] + public async Task Response_OnStartingThrows_StillCallsOnCompleted() + { + var onStartingCalled = false; + var onCompletedCalled = false; + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + httpContext.Response.OnStarting(state => + { + onStartingCalled = true; + throw new Exception("Failed OnStarting"); + }, httpContext); + httpContext.Response.OnCompleted(state => + { + onCompletedCalled = true; + Assert.Same(state, httpContext); + return Task.FromResult(0); + }, httpContext); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + Assert.True(onStartingCalled); + Assert.True(onCompletedCalled); + } + } + + [Fact] + public async Task Response_OnStartingThrowsAfterWrite_WriteThrowsAndStillCallsOnCompleted() + { + var onStartingCalled = false; + var onCompletedCalled = false; + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + httpContext.Response.OnStarting(state => + { + onStartingCalled = true; + throw new InvalidTimeZoneException("Failed OnStarting"); + }, httpContext); + httpContext.Response.OnCompleted(state => + { + onCompletedCalled = true; + Assert.Same(state, httpContext); + return Task.FromResult(0); + }, httpContext); + Assert.Throws(() => httpContext.Response.Body.Write(new byte[10], 0, 10)); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(onStartingCalled); + Assert.True(onCompletedCalled); + } + } + private async Task SendRequestAsync(string uri) { - using (HttpClient client = new HttpClient()) + using (var client = new HttpClient()) { return await client.GetAsync(uri); } diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs index 896dc42a57..69b28cd960 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -110,6 +110,39 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] + public async Task WebSocketAccept_WithOnStarting_CallbackCalled() + { + var callbackCalled = false; + var waitHandle = new ManualResetEvent(false); + bool? upgraded = null; + string address; + using (Utilities.CreateHttpServer(out address, async httpContext => + { + httpContext.Response.OnStarting(_ => + { + callbackCalled = true; + return Task.FromResult(0); + }, null); + var webSocketFeature = httpContext.Features.Get(); + Assert.NotNull(webSocketFeature); + Assert.True(webSocketFeature.IsWebSocketRequest); + await webSocketFeature.AcceptAsync(null); + upgraded = true; + waitHandle.Set(); + })) + { + using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(ConvertToWebSocketAddress(address))) + { + Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); + Assert.True(upgraded.HasValue, "Upgraded not set"); + Assert.True(upgraded.Value, "Upgrade failed"); + Assert.True(callbackCalled, "Callback not called"); + } + } + } + [ConditionalFact] [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_SendAndReceive_Success() diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 9a802091f1..3a2b14fefe 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.Net.Http.Server public class ResponseBodyTests { [Fact] - public async Task ResponseBody_BufferWriteNoHeaders_DefaultsToContentLength() + public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -24,31 +24,6 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); - context.Response.ShouldBuffer = true; - context.Response.Body.Write(new byte[10], 0, 10); - await context.Response.Body.WriteAsync(new byte[10], 0, 10); - context.Dispose(); - - HttpResponseMessage response = await responseTask; - Assert.Equal(200, (int)response.StatusCode); - Assert.Equal(new Version(1, 1), response.Version); - IEnumerable ignored; - Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); - Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); - Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); - } - } - - [Fact] - public async Task ResponseBody_NoBufferWriteNoHeaders_DefaultsToChunked() - { - string address; - using (var server = Utilities.CreateHttpServer(out address)) - { - Task responseTask = SendRequestAsync(address); - - var context = await server.AcceptAsync(); - context.Response.ShouldBuffer = false; context.Response.Body.Write(new byte[10], 0, 10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); @@ -64,7 +39,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseBody_FlushThenBuffer_DefaultsToChunkedAndTerminates() + public async Task ResponseBody_FlushThenWrite_DefaultsToChunkedAndTerminates() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -175,13 +150,7 @@ namespace Microsoft.Net.Http.Server context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); -#if !NETCOREAPP1_0 - // HttpClient retries the request because it didn't get a response. - context = await server.AcceptAsync(); - context.Response.Headers["Content-lenGth"] = " 20 "; - context.Response.Body.Write(new byte[5], 0, 5); - context.Dispose(); -#endif + await Assert.ThrowsAsync(() => responseTask); } } @@ -199,14 +168,7 @@ namespace Microsoft.Net.Http.Server context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); context.Dispose(); -#if !NETCOREAPP1_0 - // HttpClient retries the request because it didn't get a response. - context = await server.AcceptAsync(); - context.Response.Headers["Content-lenGth"] = " 10 "; - context.Response.Body.Write(new byte[5], 0, 5); - Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); - context.Dispose(); -#endif + await Assert.ThrowsAsync(() => responseTask); } } @@ -237,7 +199,7 @@ namespace Microsoft.Net.Http.Server } [Fact] - public async Task ResponseBody_WriteZeroCount_StartsResponse() + public async Task ResponseBody_WriteZeroCount_StartsChunkedResponse() { string address; using (var server = Utilities.CreateHttpServer(out address)) @@ -254,74 +216,12 @@ namespace Microsoft.Net.Http.Server Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; - Assert.True(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); - Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); } } - [Fact] - public async Task ResponseBody_WriteMoreThanBufferLimitBufferWithNoHeaders_DefaultsToChunkedAndFlushes() - { - string address; - using (var server = Utilities.CreateHttpServer(out address)) - { - Task responseTask = SendRequestAsync(address); - - var context = await server.AcceptAsync(); - context.Response.ShouldBuffer = true; - for (int i = 0; i < 4; i++) - { - context.Response.Body.Write(new byte[1020], 0, 1020); - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.HasStartedSending); - } - context.Response.Body.Write(new byte[1020], 0, 1020); - Assert.True(context.Response.HasStartedSending); - context.Response.Body.Write(new byte[1020], 0, 1020); - context.Dispose(); - - HttpResponseMessage response = await responseTask; - Assert.Equal(200, (int)response.StatusCode); - Assert.Equal(new Version(1, 1), response.Version); - IEnumerable ignored; - Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); - Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); - Assert.Equal(new byte[1020*6], await response.Content.ReadAsByteArrayAsync()); - } - } - - [Fact] - public async Task ResponseBody_WriteAsyncMoreThanBufferLimitBufferWithNoHeaders_DefaultsToChunkedAndFlushes() - { - string address; - using (var server = Utilities.CreateHttpServer(out address)) - { - Task responseTask = SendRequestAsync(address); - - var context = await server.AcceptAsync(); - context.Response.ShouldBuffer = true; - for (int i = 0; i < 4; i++) - { - await context.Response.Body.WriteAsync(new byte[1020], 0, 1020); - Assert.True(context.Response.HasStarted); - Assert.False(context.Response.HasStartedSending); - } - await context.Response.Body.WriteAsync(new byte[1020], 0, 1020); - Assert.True(context.Response.HasStartedSending); - await context.Response.Body.WriteAsync(new byte[1020], 0, 1020); - context.Dispose(); - - HttpResponseMessage response = await responseTask; - Assert.Equal(200, (int)response.StatusCode); - Assert.Equal(new Version(1, 1), response.Version); - IEnumerable ignored; - Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); - Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); - Assert.Equal(new byte[1020 * 6], await response.Content.ReadAsByteArrayAsync()); - } - } - [Fact] public async Task ResponseBody_WriteAsyncWithActiveCancellationToken_Success() { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index f4b5272d41..349f93ecfe 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -289,7 +289,6 @@ namespace Microsoft.Net.Http.Server context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); - context.Response.ShouldBuffer = true; context.Response.Body.Write(new byte[10], 0, 10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index 6ed772dc29..b29aa197a4 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -216,7 +216,7 @@ namespace Microsoft.Net.Http.Server var context = await server.AcceptAsync(); await context.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None); - Assert.True(context.Response.HasStartedSending); + Assert.True(context.Response.HasStarted); await context.Response.Body.WriteAsync(new byte[10], 0, 10, CancellationToken.None); context.Dispose(); File.Delete(emptyFilePath); From cd886802fe81853ffd4f22119b278cba2fee1ca4 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 10 Aug 2016 15:49:02 -0700 Subject: [PATCH 373/597] Fix race condition in new OnStarting and OnCompleted tests. --- .../ResponseTests.cs | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs index 8fcbe69d4e..002003ac36 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -19,6 +19,7 @@ using System; using System.IO; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; using Xunit; @@ -135,21 +136,21 @@ namespace Microsoft.AspNetCore.Server.WebListener [Fact] public async Task Response_Empty_CallsOnStartingAndOnCompleted() { - var onStartingCalled = false; - var onCompletedCalled = false; + var onStartingCalled = new ManualResetEvent(false); + var onCompletedCalled = new ManualResetEvent(false); string address; using (Utilities.CreateHttpServer(out address, httpContext => { httpContext.Response.OnStarting(state => { - onStartingCalled = true; Assert.Same(state, httpContext); + onStartingCalled.Set(); return Task.FromResult(0); }, httpContext); httpContext.Response.OnCompleted(state => { - onCompletedCalled = true; Assert.Same(state, httpContext); + onCompletedCalled.Set(); return Task.FromResult(0); }, httpContext); return Task.FromResult(0); @@ -157,28 +158,29 @@ namespace Microsoft.AspNetCore.Server.WebListener { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.True(onStartingCalled); - Assert.True(onCompletedCalled); + Assert.True(onStartingCalled.WaitOne(0)); + // Fires after the response completes + Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); } } [Fact] public async Task Response_OnStartingThrows_StillCallsOnCompleted() { - var onStartingCalled = false; - var onCompletedCalled = false; + var onStartingCalled = new ManualResetEvent(false); + var onCompletedCalled = new ManualResetEvent(false); string address; using (Utilities.CreateHttpServer(out address, httpContext => { httpContext.Response.OnStarting(state => { - onStartingCalled = true; + onStartingCalled.Set(); throw new Exception("Failed OnStarting"); }, httpContext); httpContext.Response.OnCompleted(state => { - onCompletedCalled = true; Assert.Same(state, httpContext); + onCompletedCalled.Set(); return Task.FromResult(0); }, httpContext); return Task.FromResult(0); @@ -186,28 +188,29 @@ namespace Microsoft.AspNetCore.Server.WebListener { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); - Assert.True(onStartingCalled); - Assert.True(onCompletedCalled); + Assert.True(onStartingCalled.WaitOne(0)); + // Fires after the response completes + Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); } } [Fact] public async Task Response_OnStartingThrowsAfterWrite_WriteThrowsAndStillCallsOnCompleted() { - var onStartingCalled = false; - var onCompletedCalled = false; + var onStartingCalled = new ManualResetEvent(false); + var onCompletedCalled = new ManualResetEvent(false); string address; using (Utilities.CreateHttpServer(out address, httpContext => { httpContext.Response.OnStarting(state => { - onStartingCalled = true; + onStartingCalled.Set(); throw new InvalidTimeZoneException("Failed OnStarting"); }, httpContext); httpContext.Response.OnCompleted(state => { - onCompletedCalled = true; Assert.Same(state, httpContext); + onCompletedCalled.Set(); return Task.FromResult(0); }, httpContext); Assert.Throws(() => httpContext.Response.Body.Write(new byte[10], 0, 10)); @@ -216,8 +219,9 @@ namespace Microsoft.AspNetCore.Server.WebListener { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.True(onStartingCalled); - Assert.True(onCompletedCalled); + Assert.True(onStartingCalled.WaitOne(0)); + // Fires after the response completes + Assert.True(onCompletedCalled.WaitOne(TimeSpan.FromSeconds(5))); } } From e39ea6280883ba3c32ba8e5a76aebd921b24e14b Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 18 Aug 2016 13:46:36 -0700 Subject: [PATCH 374/597] #160 Refactor options/settings --- samples/HelloWorld/Program.cs | 6 +- samples/HotAddSample/Startup.cs | 2 +- samples/SelfHostServer/Startup.cs | 8 +- .../Internal/WebListenerOptionsSetup.cs | 6 +- .../MessagePump.cs | 11 +- .../WebListenerOptions.cs | 14 +- .../AuthenticationManager.cs | 31 +++-- src/Microsoft.Net.Http.Server/LogHelper.cs | 34 ----- .../NativeInterop/RequestQueue.cs | 22 +++- .../NativeInterop/UrlGroup.cs | 13 +- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/Response.cs | 4 +- .../RequestProcessing/ResponseStream.cs | 6 +- .../TimeoutManager.cs | 26 ++-- .../UrlPrefixCollection.cs | 23 ++-- src/Microsoft.Net.Http.Server/WebListener.cs | 122 +++++------------- .../WebListenerSettings.cs | 114 ++++++++++++++++ .../RequestTests.cs | 2 +- .../ServerTests.cs | 4 +- .../Utilities.cs | 4 +- .../RequestTests.cs | 2 +- .../ServerTests.cs | 8 +- .../Utilities.cs | 9 +- 23 files changed, 275 insertions(+), 198 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/WebListenerSettings.cs diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 6ec6112781..dac0e302bd 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -16,9 +16,11 @@ namespace HelloWorld public static async Task Run(string[] args) { - using (WebListener listener = new WebListener()) + var settings = new WebListenerSettings(); + settings.UrlPrefixes.Add("http://localhost:8080"); + + using (WebListener listener = new WebListener(settings)) { - listener.UrlPrefixes.Add("http://localhost:8080"); listener.Start(); Console.WriteLine("Running..."); diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index 1fa57b5606..089b14d01d 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -16,7 +16,7 @@ namespace HotAddSample { loggerfactory.AddConsole(LogLevel.Information); - var addresses = app.ServerFeatures.Get().UrlPrefixes; + var addresses = app.ServerFeatures.Get().Settings.UrlPrefixes; addresses.Add("http://localhost:12346/pathBase/"); app.Use(async (context, next) => diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index e85fff80f9..c6a9fecf72 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -19,8 +19,8 @@ namespace SelfHostServer // Server options can be configured here instead of in Main. services.Configure(options => { - options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.None; - options.Listener.AuthenticationManager.AllowAnonymous = true; + options.ListenerSettings.Authentication.Schemes = AuthenticationSchemes.None; + options.ListenerSettings.Authentication.AllowAnonymous = true; }); } @@ -52,8 +52,8 @@ namespace SelfHostServer .UseStartup() .UseWebListener(options => { - options.Listener.AuthenticationManager.AuthenticationSchemes = AuthenticationSchemes.None; - options.Listener.AuthenticationManager.AllowAnonymous = true; + options.ListenerSettings.Authentication.Schemes = AuthenticationSchemes.None; + options.ListenerSettings.Authentication.AllowAnonymous = true; }) .Build(); diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs b/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs index eeba2f8b91..6b87fd31ad 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.Internal public void Configure(WebListenerOptions options) { - options.Listener = new Microsoft.Net.Http.Server.WebListener(_loggerFactory); + options.ListenerSettings.Logger = _loggerFactory.CreateLogger(); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs index 591b060900..3de914ea0d 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs @@ -57,15 +57,16 @@ namespace Microsoft.AspNetCore.Server.WebListener throw new ArgumentNullException(nameof(loggerFactory)); } - _listener = options.Value?.Listener ?? new Microsoft.Net.Http.Server.WebListener(loggerFactory); + var optionsInstance = options.Value; + _listener = new Microsoft.Net.Http.Server.WebListener(optionsInstance.ListenerSettings); _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); Features = new FeatureCollection(); _serverAddresses = new ServerAddressesFeature(); Features.Set(_serverAddresses); _processRequest = new Action(ProcessRequestAsync); - _maxAccepts = options.Value?.MaxAccepts ?? WebListenerOptions.DefaultMaxAccepts; - EnableResponseCaching = options.Value?.EnableResponseCaching ?? true; + _maxAccepts = optionsInstance.MaxAccepts; + EnableResponseCaching = optionsInstance.EnableResponseCaching; _shutdownSignal = new ManualResetEvent(false); } @@ -94,7 +95,7 @@ namespace Microsoft.AspNetCore.Server.WebListener _application = new ApplicationWrapper(application); - if (_listener.UrlPrefixes.Count == 0) + if (_listener.Settings.UrlPrefixes.Count == 0) { throw new InvalidOperationException("No address prefixes were defined."); } @@ -224,7 +225,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { foreach (var value in addresses) { - listener.UrlPrefixes.Add(UrlPrefix.Create(value)); + listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(value)); } } diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs index 9613f6d468..aa4bbbc0f5 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs @@ -16,6 +16,7 @@ // permissions and limitations under the License. using System; +using Microsoft.Net.Http.Server; namespace Microsoft.AspNetCore.Server.WebListener { @@ -23,10 +24,21 @@ namespace Microsoft.AspNetCore.Server.WebListener { internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; - public Microsoft.Net.Http.Server.WebListener Listener { get; set; } = new Microsoft.Net.Http.Server.WebListener(); + /// + /// Settings for the underlying WebListener instance. + /// + public WebListenerSettings ListenerSettings { get; } = new WebListenerSettings(); + /// + /// The maximum number of concurrent calls to WebListener.AcceptAsync(). + /// public int MaxAccepts { get; set; } = DefaultMaxAccepts; + /// + /// Attempts kernel mode caching for responses with eligible headers. The response may not include + /// Set-Cookie, Vary, or Pragma headers. It must include a Cache-Control header with Public and + /// either a Shared-Max-Age or Max-Age value, or an Expires header. + /// public bool EnableResponseCaching { get; set; } = true; } } diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index c1f0ed0ac1..fb8766996a 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Security.Claims; @@ -42,24 +43,21 @@ namespace Microsoft.Net.Http.Server private static readonly int AuthInfoSize = Marshal.SizeOf(); - private WebListener _server; + private UrlGroup _urlGroup; private AuthenticationSchemes _authSchemes; private bool _allowAnonymous = true; - internal AuthenticationManager(WebListener listener) + internal AuthenticationManager() { - _server = listener; } - #region Properties - - public AuthenticationSchemes AuthenticationSchemes + public AuthenticationSchemes Schemes { get { return _authSchemes; } set { _authSchemes = value; - SetServerSecurity(); + SetUrlGroupSecurity(); } } @@ -69,10 +67,21 @@ namespace Microsoft.Net.Http.Server set { _allowAnonymous = value; } } - #endregion Properties - - private unsafe void SetServerSecurity() + internal void SetUrlGroupSecurity(UrlGroup urlGroup) { + Debug.Assert(_urlGroup == null, "SetUrlGroupSecurity called more than once."); + _urlGroup = urlGroup; + SetUrlGroupSecurity(); + } + + private unsafe void SetUrlGroupSecurity() + { + if (_urlGroup == null) + { + // Not started yet. + return; + } + HttpApi.HTTP_SERVER_AUTHENTICATION_INFO authInfo = new HttpApi.HTTP_SERVER_AUTHENTICATION_INFO(); @@ -91,7 +100,7 @@ namespace Microsoft.Net.Http.Server IntPtr infoptr = new IntPtr(&authInfo); - _server.UrlGroup.SetProperty( + _urlGroup.SetProperty( HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, infoptr, (uint)AuthInfoSize); } diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index 4d4816462e..6ec1c67a7b 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -29,16 +29,6 @@ namespace Microsoft.Net.Http.Server { internal static class LogHelper { - internal static ILogger CreateLogger(ILoggerFactory factory, Type type) - { - if (factory == null) - { - return new NullLogger(); - } - - return factory.CreateLogger(type.FullName); - } - internal static void LogInfo(ILogger logger, string data) { if (logger == null) @@ -86,29 +76,5 @@ namespace Microsoft.Net.Http.Server logger.LogError(location + "; " + message); } } - - private class NullLogger : ILogger - { - public IDisposable BeginScope(TState state) - { - return new NullDispose(); - } - - public bool IsEnabled(LogLevel logLevel) - { - return false; - } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - } - - private class NullDispose : IDisposable - { - public void Dispose() - { - } - } - } } } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs b/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs index 87b07e5996..c650041703 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs @@ -16,11 +16,8 @@ // permissions and limitations under the License. using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; using System.Threading; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server @@ -32,6 +29,7 @@ namespace Microsoft.Net.Http.Server private readonly UrlGroup _urlGroup; private readonly ILogger _logger; + private bool _disposed; internal RequestQueue(UrlGroup urlGroup, ILogger logger) { @@ -66,6 +64,7 @@ namespace Microsoft.Net.Http.Server internal unsafe void AttachToUrlGroup() { + CheckDisposed(); // Set the association between request queue and url group. After this, requests for registered urls will // get delivered to this request queue. @@ -81,6 +80,7 @@ namespace Microsoft.Net.Http.Server internal unsafe void DetachFromUrlGroup() { + CheckDisposed(); // Break the association between request queue and url group. After this, requests for registered urls // will get 503s. // Note that this method may be called multiple times (Stop() and then Abort()). This @@ -100,6 +100,8 @@ namespace Microsoft.Net.Http.Server // The listener must be active for this to work. internal unsafe void SetLengthLimit(long length) { + CheckDisposed(); + var result = HttpApi.HttpSetRequestQueueProperty(Handle, HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, new IntPtr((void*)&length), (uint)Marshal.SizeOf(), 0, IntPtr.Zero); @@ -112,8 +114,22 @@ namespace Microsoft.Net.Http.Server public void Dispose() { + if (_disposed) + { + return; + } + + _disposed = true; BoundHandle.Dispose(); Handle.Dispose(); } + + private void CheckDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(this.GetType().FullName); + } + } } } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs index 385c7c61fa..23a5452122 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs @@ -50,7 +50,8 @@ namespace Microsoft.Net.Http.Server internal void SetProperty(HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) { Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); - + CheckDisposed(); + var statusCode = HttpApi.HttpSetUrlGroupProperty(Id, property, info, infosize); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) @@ -67,6 +68,7 @@ namespace Microsoft.Net.Http.Server internal void RegisterPrefix(string uriPrefix, int contextId) { LogHelper.LogInfo(_logger, "Listening on prefix: " + uriPrefix); + CheckDisposed(); var statusCode = HttpApi.HttpAddUrlToUrlGroup(Id, uriPrefix, (ulong)contextId, 0); @@ -86,6 +88,7 @@ namespace Microsoft.Net.Http.Server internal bool UnregisterPrefix(string uriPrefix) { LogHelper.LogInfo(_logger, "Stop listening on prefix: " + uriPrefix); + CheckDisposed(); var statusCode = HttpApi.HttpRemoveUrlFromUrlGroup(Id, uriPrefix, 0); @@ -115,5 +118,13 @@ namespace Microsoft.Net.Http.Server } Id = 0; } + + private void CheckDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(this.GetType().FullName); + } + } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 481f600692..6321c28b1d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -85,7 +85,7 @@ namespace Microsoft.Net.Http.Server QueryString = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } - var prefix = requestContext.Server.UrlPrefixes.GetPrefix((int)memoryBlob.RequestBlob->UrlContext); + var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)memoryBlob.RequestBlob->UrlContext); var originalPath = RequestUriBuilder.GetRequestPath(RawUrl, cookedUrlPath, RequestContext.Logger); // These paths are both unescaped already. diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 023d4edab8..3ff9af71cd 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -64,7 +64,7 @@ namespace Microsoft.Net.Http.Server _expectedBodyLength = 0; _nativeStream = null; _cacheTtl = null; - _authChallenges = RequestContext.Server.AuthenticationManager.AuthenticationSchemes; + _authChallenges = RequestContext.Server.Settings.Authentication.Schemes; } private enum ResponseState @@ -412,7 +412,7 @@ namespace Microsoft.Net.Http.Server // 401 if (StatusCode == (ushort)HttpStatusCode.Unauthorized) { - RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(RequestContext); + RequestContext.Server.Settings.Authentication.SetAuthenticationChallenge(RequestContext); } var flags = HttpApi.HTTP_FLAGS.NONE; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 04e8f16e64..be0d5ad1a8 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -171,7 +171,7 @@ namespace Microsoft.Net.Http.Server IntPtr.Zero); } - if (_requestContext.Server.IgnoreWriteExceptions) + if (_requestContext.Server.Settings.IgnoreWriteExceptions) { statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; } @@ -338,7 +338,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != ErrorCodes.ERROR_SUCCESS && statusCode != ErrorCodes.ERROR_IO_PENDING) { asyncResult.Dispose(); - if (_requestContext.Server.IgnoreWriteExceptions && started) + if (_requestContext.Server.Settings.IgnoreWriteExceptions && started) { asyncResult.Complete(); } @@ -602,7 +602,7 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) { asyncResult.Dispose(); - if (_requestContext.Server.IgnoreWriteExceptions && started) + if (_requestContext.Server.Settings.IgnoreWriteExceptions && started) { asyncResult.Complete(); } diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index 8c7155f710..9762c254a7 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -37,14 +37,12 @@ namespace Microsoft.Net.Http.Server private static readonly int TimeoutLimitSize = Marshal.SizeOf(); - private WebListener _server; + private UrlGroup _urlGroup; private int[] _timeouts; private uint _minSendBytesPerSecond; - internal TimeoutManager(WebListener listener) + internal TimeoutManager() { - _server = listener; - // We have to maintain local state since we allow applications to set individual timeouts. Native Http // API for setting timeouts expects all timeout values in every call so we have remember timeout values // to fill in the blanks. Except MinSendBytesPerSecond, local state for remaining five timeouts is @@ -180,7 +178,7 @@ namespace Microsoft.Net.Http.Server throw new ArgumentOutOfRangeException("value"); } - SetServerTimeouts(_timeouts, (uint)value); + SetUrlGroupTimeouts(_timeouts, (uint)value); _minSendBytesPerSecond = (uint)value; } } @@ -211,12 +209,24 @@ namespace Microsoft.Net.Http.Server // call succeeds, update local state. var newTimeouts = (int[])_timeouts.Clone(); newTimeouts[(int)type] = (int)timeoutValue; - SetServerTimeouts(newTimeouts, _minSendBytesPerSecond); + SetUrlGroupTimeouts(newTimeouts, _minSendBytesPerSecond); _timeouts[(int)type] = (int)timeoutValue; } - private unsafe void SetServerTimeouts(int[] timeouts, uint minSendBytesPerSecond) + internal void SetUrlGroupTimeouts(UrlGroup urlGroup) { + _urlGroup = urlGroup; + SetUrlGroupTimeouts(_timeouts, _minSendBytesPerSecond); + } + + private unsafe void SetUrlGroupTimeouts(int[] timeouts, uint minSendBytesPerSecond) + { + if (_urlGroup == null) + { + // Not started yet + return; + } + var timeoutinfo = new HttpApi.HTTP_TIMEOUT_LIMIT_INFO(); timeoutinfo.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; @@ -234,7 +244,7 @@ namespace Microsoft.Net.Http.Server var infoptr = new IntPtr(&timeoutinfo); - _server.UrlGroup.SetProperty( + _urlGroup.SetProperty( HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty, infoptr, (uint)TimeoutLimitSize); } diff --git a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs index b8f417ca14..bfef83e0d2 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Collections; using System.Collections.Generic; @@ -12,13 +11,12 @@ namespace Microsoft.Net.Http.Server /// public class UrlPrefixCollection : ICollection { - private readonly WebListener _webListener; private readonly IDictionary _prefixes = new Dictionary(1); + private UrlGroup _urlGroup; private int _nextId = 1; - internal UrlPrefixCollection(WebListener webListener) + internal UrlPrefixCollection() { - _webListener = webListener; } public int Count @@ -47,9 +45,9 @@ namespace Microsoft.Net.Http.Server lock (_prefixes) { var id = _nextId++; - if (_webListener.IsListening) + if (_urlGroup != null) { - _webListener.UrlGroup.RegisterPrefix(item.FullPrefix, id); + _urlGroup.RegisterPrefix(item.FullPrefix, id); } _prefixes.Add(id, item); } @@ -67,7 +65,7 @@ namespace Microsoft.Net.Http.Server { lock (_prefixes) { - if (_webListener.IsListening) + if (_urlGroup != null) { UnregisterAllPrefixes(); } @@ -106,9 +104,9 @@ namespace Microsoft.Net.Http.Server if (pair.Value.Equals(item)) { id = pair.Key; - if (_webListener.IsListening) + if (_urlGroup != null) { - _webListener.UrlGroup.UnregisterPrefix(pair.Value.FullPrefix); + _urlGroup.UnregisterPrefix(pair.Value.FullPrefix); } } } @@ -134,15 +132,16 @@ namespace Microsoft.Net.Http.Server return GetEnumerator(); } - internal void RegisterAllPrefixes() + internal void RegisterAllPrefixes(UrlGroup urlGroup) { lock (_prefixes) { + _urlGroup = urlGroup; // go through the uri list and register for each one of them foreach (var pair in _prefixes) { // We'll get this index back on each request and use it to look up the prefix to calculate PathBase. - _webListener.UrlGroup.RegisterPrefix(pair.Value.FullPrefix, pair.Key); + _urlGroup.RegisterPrefix(pair.Value.FullPrefix, pair.Key); } } } @@ -155,7 +154,7 @@ namespace Microsoft.Net.Http.Server foreach (var prefix in _prefixes.Values) { // ignore possible failures - _webListener.UrlGroup.UnregisterPrefix(prefix.FullPrefix); + _urlGroup.UnregisterPrefix(prefix.FullPrefix); } } } diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 5f92de5fae..f7dde384fc 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -24,7 +24,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -36,8 +35,6 @@ namespace Microsoft.Net.Http.Server /// public sealed class WebListener : IDisposable { - private const long DefaultRequestQueueLength = 1000; // Http.sys default. - // Win8# 559317 fixed a bug in Http.sys's HttpReceiveClientCertificate method. // Without this fix IOCP callbacks were not being called although ERROR_IO_PENDING was // returned from HttpReceiveClientCertificate when using the @@ -53,49 +50,39 @@ namespace Microsoft.Net.Http.Server // 0.5 seconds per request. Respond with a 400 Bad Request. private const int UnknownHeaderLimit = 1000; - private ILogger _logger; - private volatile State _state; // m_State is set only within lock blocks, but often read outside locks. - private bool _ignoreWriteExceptions; private ServerSession _serverSession; private UrlGroup _urlGroup; private RequestQueue _requestQueue; - private TimeoutManager _timeoutManager; - private AuthenticationManager _authManager; private DisconnectListener _disconnectListener; private object _internalLock; - private UrlPrefixCollection _urlPrefixes; - - // The native request queue - private long? _requestQueueLength; - public WebListener() - : this(null) + : this(new WebListenerSettings()) { } - public WebListener(ILoggerFactory factory) + public WebListener(WebListenerSettings settings) { + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + if (!HttpApi.Supported) { throw new PlatformNotSupportedException(); } - _logger = LogHelper.CreateLogger(factory, typeof(WebListener)); + Debug.Assert(HttpApi.ApiVersion == HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version"); - Debug.Assert(HttpApi.ApiVersion == - HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version"); + Settings = settings; _state = State.Stopped; _internalLock = new object(); - _urlPrefixes = new UrlPrefixCollection(this); - _timeoutManager = new TimeoutManager(this); - _authManager = new AuthenticationManager(this); - // V2 initialization sequence: // 1. Create server session // 2. Create url group @@ -107,11 +94,11 @@ namespace Microsoft.Net.Http.Server { _serverSession = new ServerSession(); - _urlGroup = new UrlGroup(_serverSession, _logger); + _urlGroup = new UrlGroup(_serverSession, Logger); - _requestQueue = new RequestQueue(_urlGroup, _logger); + _requestQueue = new RequestQueue(_urlGroup, Logger); - _disconnectListener = new DisconnectListener(_requestQueue, _logger); + _disconnectListener = new DisconnectListener(_requestQueue, Logger); } catch (Exception exception) { @@ -119,7 +106,7 @@ namespace Microsoft.Net.Http.Server _requestQueue?.Dispose(); _urlGroup?.Dispose(); _serverSession?.Dispose(); - LogHelper.LogException(_logger, ".Ctor", exception); + LogHelper.LogException(Logger, ".Ctor", exception); throw; } } @@ -133,7 +120,7 @@ namespace Microsoft.Net.Http.Server internal ILogger Logger { - get { return _logger; } + get { return Settings.Logger; } } internal UrlGroup UrlGroup @@ -151,66 +138,13 @@ namespace Microsoft.Net.Http.Server get { return _disconnectListener; } } - // TODO: https://github.com/aspnet/WebListener/issues/173 - internal bool IgnoreWriteExceptions - { - get { return _ignoreWriteExceptions; } - set - { - CheckDisposed(); - _ignoreWriteExceptions = value; - } - } - - public UrlPrefixCollection UrlPrefixes - { - get { return _urlPrefixes; } - } - - /// - /// Exposes the Http.Sys timeout configurations. These may also be configured in the registry. - /// - public TimeoutManager TimeoutManager - { - get { return _timeoutManager; } - } - - /// - /// Http.Sys authentication settings. - /// - public AuthenticationManager AuthenticationManager - { - get { return _authManager; } - } + public WebListenerSettings Settings { get; } public bool IsListening { get { return _state == State.Started; } } - /// - /// Sets the maximum number of requests that will be queued up in Http.Sys. - /// - /// - public void SetRequestQueueLimit(long limit) - { - CheckDisposed(); - if (limit <= 0) - { - throw new ArgumentOutOfRangeException("limit", limit, string.Empty); - } - - // Don't try to change it if the new limit is the same - if ((!_requestQueueLength.HasValue && limit == DefaultRequestQueueLength) - || (_requestQueueLength.HasValue && limit == _requestQueueLength.Value)) - { - return; - } - - _requestQueueLength = limit; - _requestQueue.SetLengthLimit(_requestQueueLength.Value); - } - /// /// Start accepting incoming requests. /// @@ -218,7 +152,7 @@ namespace Microsoft.Net.Http.Server { CheckDisposed(); - LogHelper.LogInfo(_logger, "Start"); + LogHelper.LogInfo(Logger, "Start"); // Make sure there are no race conditions between Start/Stop/Abort/Close/Dispose. // Start needs to setup all resources. Abort/Stop must not interfere while Start is @@ -233,12 +167,16 @@ namespace Microsoft.Net.Http.Server return; } + Settings.Authentication.SetUrlGroupSecurity(UrlGroup); + Settings.Timeouts.SetUrlGroupTimeouts(UrlGroup); + Settings.SetRequestQueueLimit(RequestQueue); + _requestQueue.AttachToUrlGroup(); // All resources are set up correctly. Now add all prefixes. try { - _urlPrefixes.RegisterAllPrefixes(); + Settings.UrlPrefixes.RegisterAllPrefixes(UrlGroup); } catch (WebListenerException) { @@ -254,7 +192,7 @@ namespace Microsoft.Net.Http.Server // Make sure the HttpListener instance can't be used if Start() failed. _state = State.Disposed; DisposeInternal(); - LogHelper.LogException(_logger, "Start", exception); + LogHelper.LogException(Logger, "Start", exception); throw; } } @@ -272,7 +210,7 @@ namespace Microsoft.Net.Http.Server return; } - _urlPrefixes.UnregisterAllPrefixes(); + Settings.UrlPrefixes.UnregisterAllPrefixes(); _state = State.Stopped; @@ -281,7 +219,7 @@ namespace Microsoft.Net.Http.Server } catch (Exception exception) { - LogHelper.LogException(_logger, "Stop", exception); + LogHelper.LogException(Logger, "Stop", exception); throw; } } @@ -309,14 +247,14 @@ namespace Microsoft.Net.Http.Server { return; } - LogHelper.LogInfo(_logger, "Dispose"); + LogHelper.LogInfo(Logger, "Dispose"); Stop(); DisposeInternal(); } catch (Exception exception) { - LogHelper.LogException(_logger, "Dispose", exception); + LogHelper.LogException(Logger, "Dispose", exception); throw; } finally @@ -371,7 +309,7 @@ namespace Microsoft.Net.Http.Server } catch (Exception exception) { - LogHelper.LogException(_logger, "GetContextAsync", exception); + LogHelper.LogException(Logger, "GetContextAsync", exception); throw; } @@ -392,10 +330,10 @@ namespace Microsoft.Net.Http.Server internal unsafe bool ValidateAuth(NativeRequestContext requestMemory) { var requestV2 = (HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob; - if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) + if (!Settings.Authentication.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) { SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, - AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationSchemes)); + AuthenticationManager.GenerateChallenges(Settings.Authentication.Schemes)); return false; } return true; @@ -509,7 +447,7 @@ namespace Microsoft.Net.Http.Server } } - internal void CheckDisposed() + private void CheckDisposed() { if (_state == State.Disposed) { diff --git a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs new file mode 100644 index 0000000000..dd65bc5c3f --- /dev/null +++ b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions.Internal; + +namespace Microsoft.Net.Http.Server +{ + public class WebListenerSettings + { + private const long DefaultRequestQueueLength = 1000; // Http.sys default. + + // The native request queue + private long _requestQueueLength = DefaultRequestQueueLength; + private RequestQueue _requestQueue; + private ILogger _logger = NullLogger.Instance; + + public WebListenerSettings() + { + } + + /// + /// The logger that will be used to create the WebListener instance. This should not be changed + /// after creating the listener. + /// + public ILogger Logger + { + get { return _logger; } + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + _logger = value; + } + } + + /// + /// The url prefixes to register with Http.Sys. These may be modified at any time prior to disposing + /// the listener. + /// + public UrlPrefixCollection UrlPrefixes { get; } = new UrlPrefixCollection(); + + /// + /// Http.Sys authentication settings. These may be modified at any time prior to disposing + /// the listener. + /// + public AuthenticationManager Authentication { get; } = new AuthenticationManager(); + + /// + /// Exposes the Http.Sys timeout configurations. These may also be configured in the registry. + /// These may be modified at any time prior to disposing the listener. + /// + public TimeoutManager Timeouts { get; } = new TimeoutManager(); + + + // TODO: https://github.com/aspnet/WebListener/issues/173 + /// + /// Gets or Sets if response body writes that fail due to client disconnects should throw exceptions or + /// complete normally. The default is true. + /// + internal bool IgnoreWriteExceptions { get; set; } = true; + + /// + /// Gets or sets the maximum number of requests that will be queued up in Http.Sys. + /// + public long RequestQueueLimit + { + get + { + return _requestQueueLength; + } + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty); + } + + if (_requestQueue != null) + { + _requestQueue.SetLengthLimit(_requestQueueLength); + } + // Only store it if it succeeds or hasn't started yet + _requestQueueLength = value; + } + } + + internal void SetRequestQueueLimit(RequestQueue requestQueue) + { + _requestQueue = requestQueue; + if (_requestQueueLength != DefaultRequestQueueLength) + { + _requestQueue.SetLengthLimit(_requestQueueLength); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index 08d075089d..62b1f18d4f 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.Server.WebListener foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - server.Listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); + server.Listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); } server.Start(new DummyApplication(app)); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs index a439324a81..6acf44068d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs @@ -256,8 +256,8 @@ namespace Microsoft.AspNetCore.Server.WebListener using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); - server.Listener.UrlPrefixes.Add(UrlPrefix.Create(address)); - server.Listener.SetRequestQueueLimit(1001); + server.Listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(address)); + server.Listener.Settings.RequestQueueLimit = 1001; using (server) { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs index 35dbaa848b..02a933d838 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs @@ -67,8 +67,8 @@ namespace Microsoft.AspNetCore.Server.WebListener var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); server.Features.Get().Addresses.Add(baseAddress); - server.Listener.AuthenticationManager.AuthenticationSchemes = authType; - server.Listener.AuthenticationManager.AllowAnonymous = allowAnonymous; + server.Listener.Settings.Authentication.Schemes = authType; + server.Listener.Settings.Authentication.AllowAnonymous = allowAnonymous; try { server.Start(new DummyApplication(app)); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index d69ac9ee81..31e5e850bf 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -136,7 +136,7 @@ namespace Microsoft.Net.Http.Server var uriBuilder = new UriBuilder(root); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - server.UrlPrefixes.Add(UrlPrefix.Create(uriBuilder.Scheme, uriBuilder.Host, uriBuilder.Port, path)); + server.Settings.UrlPrefixes.Add(UrlPrefix.Create(uriBuilder.Scheme, uriBuilder.Host, uriBuilder.Port, path)); } server.Start(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 6b444e4ba6..332774d211 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -171,7 +171,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.SetRequestQueueLimit(1001); + server.Settings.RequestQueueLimit = 1001; var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); @@ -199,7 +199,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(string.Empty, response); address += "pathbase/"; - server.UrlPrefixes.Add(address); + server.Settings.UrlPrefixes.Add(address); responseTask = SendRequestAsync(address); @@ -220,7 +220,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServer(out address)) { address += "pathbase/"; - server.UrlPrefixes.Add(address); + server.Settings.UrlPrefixes.Add(address); var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); @@ -231,7 +231,7 @@ namespace Microsoft.Net.Http.Server var response = await responseTask; Assert.Equal(string.Empty, response); - Assert.True(server.UrlPrefixes.Remove(address)); + Assert.True(server.Settings.UrlPrefixes.Remove(address)); responseTask = SendRequestAsync(address); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs index 73dc5466b7..3ba29a660a 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs @@ -17,8 +17,8 @@ namespace Microsoft.Net.Http.Server internal static WebListener CreateHttpAuthServer(AuthenticationSchemes authScheme, bool allowAnonymos, out string baseAddress) { var listener = CreateHttpServer(out baseAddress); - listener.AuthenticationManager.AuthenticationSchemes = authScheme; - listener.AuthenticationManager.AllowAnonymous = allowAnonymos; + listener.Settings.Authentication.Schemes = authScheme; + listener.Settings.Authentication.AllowAnonymous = allowAnonymos; return listener; } @@ -45,7 +45,7 @@ namespace Microsoft.Net.Http.Server root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; baseAddress = prefix.ToString(); var listener = new WebListener(); - listener.UrlPrefixes.Add(prefix); + listener.Settings.UrlPrefixes.Add(prefix); try { listener.Start(); @@ -61,7 +61,6 @@ namespace Microsoft.Net.Http.Server throw new Exception("Failed to locate a free port."); } - internal static WebListener CreateHttpsServer() { return CreateServer("https", "localhost", 9090, string.Empty); @@ -70,7 +69,7 @@ namespace Microsoft.Net.Http.Server internal static WebListener CreateServer(string scheme, string host, int port, string path) { WebListener listener = new WebListener(); - listener.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); + listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); listener.Start(); return listener; } From 9f1476aea89d1996f7c85b8fdac6bb034e25b672 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 19 Aug 2016 10:19:33 -0700 Subject: [PATCH 375/597] #230 Disable TLS token binding pending updates --- .../FeatureContext.cs | 6 +++--- .../StandardFeatureCollection.cs | 2 +- .../NativeInterop/TokenBindingUtil.cs | 1 + .../RequestProcessing/Request.cs | 19 +++++++++++-------- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index 2d9fe77c77..b443d1496a 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.WebListener IHttpResponseFeature, IHttpSendFileFeature, ITlsConnectionFeature, - ITlsTokenBindingFeature, + // ITlsTokenBindingFeature, TODO: https://github.com/aspnet/WebListener/issues/231 IHttpBufferingFeature, IHttpRequestLifetimeFeature, IHttpWebSocketFeature, @@ -328,7 +328,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { return Request.IsHttps ? this : null; } - + /* TODO: https://github.com/aspnet/WebListener/issues/231 byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId() { return Request.GetProvidedTokenBindingId(); @@ -343,7 +343,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { return Request.IsHttps ? this : null; } - + */ void IHttpBufferingFeature.DisableRequestBuffering() { // There is no request buffering. diff --git a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs index 274503edee..1c53ca1055 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { typeof(IHttpResponseFeature), _identityFunc }, { typeof(IHttpSendFileFeature), _identityFunc }, { typeof(ITlsConnectionFeature), ctx => ctx.GetTlsConnectionFeature() }, - { typeof(ITlsTokenBindingFeature), ctx => ctx.GetTlsTokenBindingFeature() }, + // { typeof(ITlsTokenBindingFeature), ctx => ctx.GetTlsTokenBindingFeature() }, TODO: https://github.com/aspnet/WebListener/issues/231 { typeof(IHttpBufferingFeature), _identityFunc }, { typeof(IHttpRequestLifetimeFeature), _identityFunc }, { typeof(IHttpUpgradeFeature), _identityFunc }, diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs index 2b6fe417be..06df695c90 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs @@ -25,6 +25,7 @@ namespace Microsoft.Net.Http.Server /// /// Contains helpers for dealing with TLS token binding. /// + // TODO: https://github.com/aspnet/WebListener/issues/231 internal unsafe static class TokenBindingUtil { private static byte[] ExtractIdentifierBlob(TOKENBINDING_RESULT_DATA* pTokenBindingResultData) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 6321c28b1d..e184ac29c2 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -38,8 +38,9 @@ namespace Microsoft.Net.Http.Server private NativeRequestContext _nativeRequestContext; private X509Certificate2 _clientCert; - private byte[] _providedTokenBindingId; - private byte[] _referredTokenBindingId; + // TODO: https://github.com/aspnet/WebListener/issues/231 + // private byte[] _providedTokenBindingId; + // private byte[] _referredTokenBindingId; private BoundaryType _contentBoundaryType; private long? _contentLength; @@ -125,7 +126,7 @@ namespace Microsoft.Net.Http.Server var requestV2 = (HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; User = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount); - GetTlsTokenBindingInfo(); + // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/WebListener/issues/231 // Finished directly accessing the HTTP_REQUEST structure. _nativeRequestContext.ReleasePins(); @@ -328,17 +329,17 @@ namespace Microsoft.Net.Http.Server } return _clientCert; } - - public byte[] GetProvidedTokenBindingId() + /* TODO: https://github.com/aspnet/WebListener/issues/231 + private byte[] GetProvidedTokenBindingId() { return _providedTokenBindingId; } - public byte[] GetReferredTokenBindingId() + private byte[] GetReferredTokenBindingId() { return _referredTokenBindingId; } - + */ // Only call from the constructor so we can directly access the native request blob. // This requires Windows 10 and the following reg key: // Set Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters to Value: EnableSslTokenBinding = 1 [DWORD] @@ -347,6 +348,8 @@ namespace Microsoft.Net.Http.Server // Value: "iexplore.exe"=dword:0x00000001 // Key: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_ENABLE_TOKEN_BINDING // Value: "iexplore.exe"=dword:00000001 + // TODO: https://github.com/aspnet/WebListener/issues/231 + /* private unsafe void GetTlsTokenBindingInfo() { var nativeRequest = (HttpApi.HTTP_REQUEST_V2*)_nativeRequestContext.RequestBlob; @@ -360,7 +363,7 @@ namespace Microsoft.Net.Http.Server } } } - + */ // should only be called from RequestContext internal void Dispose() { From efef52a0ada549175741265726689839ecbda766 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 19 Aug 2016 13:57:42 -0700 Subject: [PATCH 376/597] #216 Lazy feature initialization --- .../FeatureContext.cs | 300 +++++++++--------- .../RequestTests.cs | 134 +++++++- 2 files changed, 277 insertions(+), 157 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index b443d1496a..223cf3a9ac 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -19,7 +19,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; using System.Net; using System.Net.WebSockets; using System.Security.Claims; @@ -63,17 +62,19 @@ namespace Microsoft.AspNetCore.Server.WebListener private string _rawTarget; private IPAddress _remoteIpAddress; private IPAddress _localIpAddress; - private int? _remotePort; - private int? _localPort; + private int _remotePort; + private int _localPort; private string _connectionId; - private string _requestId; + private string _traceIdentitfier; private X509Certificate2 _clientCert; private ClaimsPrincipal _user; private IAuthenticationHandler _authHandler; - private CancellationToken? _disconnectToken; + private CancellationToken _disconnectToken; private Stream _responseStream; private IHeaderDictionary _responseHeaders; + private Fields _initializedFields; + private List, object>> _onStartingActions = new List, object>>(); private List, object>> _onCompletedActions = new List, object>>(); private bool _responseStarted; @@ -85,91 +86,95 @@ namespace Microsoft.AspNetCore.Server.WebListener _features = new FeatureCollection(new StandardFeatureCollection(this)); _authHandler = new AuthenticationHandler(requestContext); _enableResponseCaching = enableResponseCaching; + + // Pre-initialize any fields that are not lazy at the lower level. + _requestHeaders = new HeaderDictionary(Request.Headers); + _httpMethod = Request.Method; + _path = Request.Path; + _pathBase = Request.PathBase; + _query = Request.QueryString; + _rawTarget = Request.RawUrl; + _scheme = Request.Scheme; + _user = _requestContext.User; + _responseStream = new ResponseStream(requestContext.Response.Body, OnStart); + _responseHeaders = new HeaderDictionary(Response.Headers); } - internal IFeatureCollection Features + internal IFeatureCollection Features => _features; + + internal object RequestContext => _requestContext; + + private Request Request => _requestContext.Request; + + private Response Response => _requestContext.Response; + + [Flags] + // Fields that may be lazy-initialized + private enum Fields { - get { return _features; } + None = 0x0, + Protocol = 0x1, + RequestBody = 0x2, + RequestAborted = 0x4, + LocalIpAddress = 0x8, + RemoteIpAddress = 0x10, + LocalPort = 0x20, + RemotePort = 0x40, + ConnectionId = 0x80, + ClientCertificate = 0x100, + TraceIdentifier = 0x200, } - internal object RequestContext + private bool IsNotInitialized(Fields field) { - get { return _requestContext; } + return (_initializedFields & field) != field; } - private Request Request + private void SetInitialized(Fields field) { - get { return _requestContext.Request; } - } - - private Response Response - { - get { return _requestContext.Response; } + _initializedFields |= field; } Stream IHttpRequestFeature.Body { get { - if (_requestBody == null) + if (IsNotInitialized(Fields.RequestBody)) { _requestBody = Request.Body; + SetInitialized(Fields.RequestBody); } return _requestBody; } - set { _requestBody = value; } + set + { + _requestBody = value; + SetInitialized(Fields.RequestBody); + } } IHeaderDictionary IHttpRequestFeature.Headers { - get - { - if (_requestHeaders == null) - { - _requestHeaders = new HeaderDictionary(Request.Headers); - } - return _requestHeaders; - } + get { return _requestHeaders; } set { _requestHeaders = value; } } string IHttpRequestFeature.Method { - get - { - if (_httpMethod == null) - { - _httpMethod = Request.Method; - } - return _httpMethod; - } + get { return _httpMethod; } set { _httpMethod = value; } } string IHttpRequestFeature.Path { - get - { - if (_path == null) - { - _path = Request.Path; - } - return _path; - } + get { return _path; } set { _path = value; } } string IHttpRequestFeature.PathBase { - get - { - if (_pathBase == null) - { - _pathBase = Request.PathBase; - } - return _pathBase; - } + get { return _pathBase; } set { _pathBase = value; } } @@ -177,63 +182,47 @@ namespace Microsoft.AspNetCore.Server.WebListener { get { - if (_httpProtocolVersion == null) + if (IsNotInitialized(Fields.Protocol)) { - if (Request.ProtocolVersion.Major == 1) + var protocol = Request.ProtocolVersion; + if (protocol.Major == 1 && protocol.Minor == 1) { - if (Request.ProtocolVersion.Minor == 1) - { - _httpProtocolVersion = "HTTP/1.1"; - } - else if (Request.ProtocolVersion.Minor == 0) - { - _httpProtocolVersion = "HTTP/1.0"; - } + _httpProtocolVersion = "HTTP/1.1"; } - - _httpProtocolVersion = "HTTP/" + Request.ProtocolVersion.ToString(2); + else if (protocol.Major == 1 && protocol.Minor == 0) + { + _httpProtocolVersion = "HTTP/1.0"; + } + else + { + _httpProtocolVersion = "HTTP/" + protocol.ToString(2); + } + SetInitialized(Fields.Protocol); } return _httpProtocolVersion; } - set { _httpProtocolVersion = value; } + set + { + _httpProtocolVersion = value; + SetInitialized(Fields.Protocol); + } } string IHttpRequestFeature.QueryString { - get - { - if (_query == null) - { - _query = Request.QueryString; - } - return _query; - } + get { return _query; } set { _query = value; } } string IHttpRequestFeature.RawTarget { - get - { - if (_rawTarget == null) - { - _rawTarget = Request.RawUrl; - } - return _rawTarget; - } + get { return _rawTarget; } set { _rawTarget = value; } } string IHttpRequestFeature.Scheme { - get - { - if (_scheme == null) - { - _scheme = Request.Scheme; - } - return _scheme; - } + get { return _scheme; } set { _scheme = value; } } @@ -241,85 +230,116 @@ namespace Microsoft.AspNetCore.Server.WebListener { get { - if (_localIpAddress == null) + if (IsNotInitialized(Fields.LocalIpAddress)) { _localIpAddress = Request.LocalIpAddress; + SetInitialized(Fields.LocalIpAddress); } return _localIpAddress; } - set { _localIpAddress = value; } + set + { + _localIpAddress = value; + SetInitialized(Fields.LocalIpAddress); + } } IPAddress IHttpConnectionFeature.RemoteIpAddress { get { - if (_remoteIpAddress == null) + if (IsNotInitialized(Fields.RemoteIpAddress)) { _remoteIpAddress = Request.RemoteIpAddress; + SetInitialized(Fields.RemoteIpAddress); } return _remoteIpAddress; } - set { _remoteIpAddress = value; } + set + { + _remoteIpAddress = value; + SetInitialized(Fields.RemoteIpAddress); + } } int IHttpConnectionFeature.LocalPort { get { - if (_localPort == null) + if (IsNotInitialized(Fields.LocalPort)) { _localPort = Request.LocalPort; + SetInitialized(Fields.LocalPort); } - return _localPort.Value; + return _localPort; + } + set + { + _localPort = value; + SetInitialized(Fields.LocalPort); } - set { _localPort = value; } } int IHttpConnectionFeature.RemotePort { get { - if (_remotePort == null) + if (IsNotInitialized(Fields.RemotePort)) { _remotePort = Request.RemotePort; + SetInitialized(Fields.RemotePort); } - return _remotePort.Value; + return _remotePort; + } + set + { + _remotePort = value; + SetInitialized(Fields.RemotePort); } - set { _remotePort = value; } } string IHttpConnectionFeature.ConnectionId { get { - if (_connectionId == null) + if (IsNotInitialized(Fields.ConnectionId)) { _connectionId = Request.ConnectionId.ToString(CultureInfo.InvariantCulture); + SetInitialized(Fields.ConnectionId); } return _connectionId; } - set { _connectionId = value; } + set + { + _connectionId = value; + SetInitialized(Fields.ConnectionId); + } } X509Certificate2 ITlsConnectionFeature.ClientCertificate { get { - if (_clientCert == null) + if (IsNotInitialized(Fields.ClientCertificate)) { _clientCert = Request.GetClientCertificateAsync().Result; // TODO: Sync; + SetInitialized(Fields.ClientCertificate); } return _clientCert; } - set { _clientCert = value; } + set + { + _clientCert = value; + SetInitialized(Fields.ClientCertificate); + } } async Task ITlsConnectionFeature.GetClientCertificateAsync(CancellationToken cancellationToken) { - if (_clientCert == null) + if (IsNotInitialized(Fields.ClientCertificate)) { _clientCert = await Request.GetClientCertificateAsync(cancellationToken); + SetInitialized(Fields.ClientCertificate); } return _clientCert; } @@ -329,15 +349,9 @@ namespace Microsoft.AspNetCore.Server.WebListener return Request.IsHttps ? this : null; } /* TODO: https://github.com/aspnet/WebListener/issues/231 - byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId() - { - return Request.GetProvidedTokenBindingId(); - } + byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId() => Request.GetProvidedTokenBindingId(); - byte[] ITlsTokenBindingFeature.GetReferredTokenBindingId() - { - return Request.GetReferredTokenBindingId(); - } + byte[] ITlsTokenBindingFeature.GetReferredTokenBindingId() => Request.GetReferredTokenBindingId(); internal ITlsTokenBindingFeature GetTlsTokenBindingFeature() { @@ -356,34 +370,17 @@ namespace Microsoft.AspNetCore.Server.WebListener Stream IHttpResponseFeature.Body { - get - { - if (_responseStream == null) - { - _responseStream = Response.Body; - } - return _responseStream; - } + get { return _responseStream; } set { _responseStream = value; } } IHeaderDictionary IHttpResponseFeature.Headers { - get - { - if (_responseHeaders == null) - { - _responseHeaders = new HeaderDictionary(Response.Headers); - } - return _responseHeaders; - } + get { return _responseHeaders; } set { _responseHeaders = value; } } - bool IHttpResponseFeature.HasStarted - { - get { return Response.HasStarted; } - } + bool IHttpResponseFeature.HasStarted => Response.HasStarted; void IHttpResponseFeature.OnStarting(Func callback, object state) { @@ -435,24 +432,23 @@ namespace Microsoft.AspNetCore.Server.WebListener { get { - if (!_disconnectToken.HasValue) + if (IsNotInitialized(Fields.RequestAborted)) { _disconnectToken = _requestContext.DisconnectToken; + SetInitialized(Fields.RequestAborted); } - return _disconnectToken.Value; + return _disconnectToken; + } + set + { + _disconnectToken = value; + SetInitialized(Fields.RequestAborted); } - set { _disconnectToken = value; } } - void IHttpRequestLifetimeFeature.Abort() - { - _requestContext.Abort(); - } + void IHttpRequestLifetimeFeature.Abort() => _requestContext.Abort(); - bool IHttpUpgradeFeature.IsUpgradableRequest - { - get { return _requestContext.IsUpgradableRequest; } - } + bool IHttpUpgradeFeature.IsUpgradableRequest => _requestContext.IsUpgradableRequest; async Task IHttpUpgradeFeature.UpgradeAsync() { @@ -477,14 +473,7 @@ namespace Microsoft.AspNetCore.Server.WebListener ClaimsPrincipal IHttpAuthenticationFeature.User { - get - { - if (_user == null) - { - _user = _requestContext.User; - } - return _user; - } + get { return _user; } set { _user = value; } } @@ -498,13 +487,18 @@ namespace Microsoft.AspNetCore.Server.WebListener { get { - if (_requestId == null) + if (IsNotInitialized(Fields.TraceIdentifier)) { - _requestId = _requestContext.TraceIdentifier.ToString(); + _traceIdentitfier = _requestContext.TraceIdentifier.ToString(); + SetInitialized(Fields.TraceIdentifier); } - return _requestId; + return _traceIdentitfier; + } + set + { + _traceIdentitfier = value; + SetInitialized(Fields.TraceIdentifier); } - set { _requestId = value; } } internal async Task OnStart() diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index 62b1f18d4f..ce7db01208 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -17,6 +17,7 @@ using System; using System.IO; +using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Text; @@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.WebListener public class RequestTests { [Fact] - public async Task Request_SimpleGet_Success() + public async Task Request_SimpleGet_ExpectedFieldsSet() { string root; using (Utilities.CreateHttpServerReturnRoot("/basepath", out root, httpContext => @@ -54,14 +55,12 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal("/basepath/SomePath?SomeQuery", requestInfo.RawTarget); Assert.Equal("HTTP/1.1", requestInfo.Protocol); - // Server Keys - // TODO: Assert.NotNull(httpContext.Get>("server.Capabilities")); - var connectionInfo = httpContext.Features.Get(); Assert.Equal("::1", connectionInfo.RemoteIpAddress.ToString()); Assert.NotEqual(0, connectionInfo.RemotePort); Assert.Equal("::1", connectionInfo.LocalIpAddress.ToString()); Assert.NotEqual(0, connectionInfo.LocalPort); + Assert.NotNull(connectionInfo.ConnectionId); // Trace identifier var requestIdentifierFeature = httpContext.Features.Get(); @@ -83,6 +82,133 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + [Fact] + public async Task Request_FieldsCanBeSet_Set() + { + string root; + using (Utilities.CreateHttpServerReturnRoot("/basepath", out root, httpContext => + { + try + { + var requestInfo = httpContext.Features.Get(); + + // Request Keys + requestInfo.Method = "TEST"; + Assert.Equal("TEST", requestInfo.Method); + requestInfo.Body = new MemoryStream(); + Assert.IsType(requestInfo.Body); + var customHeaders = new HeaderDictionary(new HeaderCollection()); + requestInfo.Headers = customHeaders; + Assert.Same(customHeaders, requestInfo.Headers); + requestInfo.Scheme = "abcd"; + Assert.Equal("abcd", requestInfo.Scheme); + requestInfo.PathBase = "/customized/Base"; + Assert.Equal("/customized/Base", requestInfo.PathBase); + requestInfo.Path = "/customized/Path"; + Assert.Equal("/customized/Path", requestInfo.Path); + requestInfo.QueryString = "?customizedQuery"; + Assert.Equal("?customizedQuery", requestInfo.QueryString); + requestInfo.RawTarget = "/customized/raw?Target"; + Assert.Equal("/customized/raw?Target", requestInfo.RawTarget); + requestInfo.Protocol = "Custom/2.0"; + Assert.Equal("Custom/2.0", requestInfo.Protocol); + + var connectionInfo = httpContext.Features.Get(); + connectionInfo.RemoteIpAddress = IPAddress.Broadcast; + Assert.Equal(IPAddress.Broadcast, connectionInfo.RemoteIpAddress); + connectionInfo.RemotePort = 12345; + Assert.Equal(12345, connectionInfo.RemotePort); + connectionInfo.LocalIpAddress = IPAddress.Any; + Assert.Equal(IPAddress.Any, connectionInfo.LocalIpAddress); + connectionInfo.LocalPort = 54321; + Assert.Equal(54321, connectionInfo.LocalPort); + connectionInfo.ConnectionId = "CustomId"; + Assert.Equal("CustomId", connectionInfo.ConnectionId); + + // Trace identifier + var requestIdentifierFeature = httpContext.Features.Get(); + Assert.NotNull(requestIdentifierFeature); + requestIdentifierFeature.TraceIdentifier = "customTrace"; + Assert.Equal("customTrace", requestIdentifierFeature.TraceIdentifier); + + // Note: Response keys are validated in the ResponseTests + } + catch (Exception ex) + { + byte[] body = Encoding.ASCII.GetBytes(ex.ToString()); + httpContext.Response.Body.Write(body, 0, body.Length); + } + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(root + "/basepath/SomePath?SomeQuery"); + Assert.Equal(string.Empty, response); + } + } + + [Fact] + public async Task Request_FieldsCanBeSetToNull_Set() + { + string root; + using (Utilities.CreateHttpServerReturnRoot("/basepath", out root, httpContext => + { + try + { + var requestInfo = httpContext.Features.Get(); + + // Request Keys + requestInfo.Method = null; + Assert.Null(requestInfo.Method); + requestInfo.Body = null; + Assert.Null(requestInfo.Body); + requestInfo.Headers = null; + Assert.Null(requestInfo.Headers); + requestInfo.Scheme = null; + Assert.Null(requestInfo.Scheme); + requestInfo.PathBase = null; + Assert.Null(requestInfo.PathBase); + requestInfo.Path = null; + Assert.Null(requestInfo.Path); + requestInfo.QueryString = null; + Assert.Null(requestInfo.QueryString); + requestInfo.RawTarget = null; + Assert.Null(requestInfo.RawTarget); + requestInfo.Protocol = null; + Assert.Null(requestInfo.Protocol); + + var connectionInfo = httpContext.Features.Get(); + connectionInfo.RemoteIpAddress = null; + Assert.Null(connectionInfo.RemoteIpAddress); + connectionInfo.RemotePort = -1; + Assert.Equal(-1, connectionInfo.RemotePort); + connectionInfo.LocalIpAddress = null; + Assert.Null(connectionInfo.LocalIpAddress); + connectionInfo.LocalPort = -1; + Assert.Equal(-1, connectionInfo.LocalPort); + connectionInfo.ConnectionId = null; + Assert.Null(connectionInfo.ConnectionId); + + // Trace identifier + var requestIdentifierFeature = httpContext.Features.Get(); + Assert.NotNull(requestIdentifierFeature); + requestIdentifierFeature.TraceIdentifier = null; + Assert.Null(requestIdentifierFeature.TraceIdentifier); + + // Note: Response keys are validated in the ResponseTests + } + catch (Exception ex) + { + byte[] body = Encoding.ASCII.GetBytes(ex.ToString()); + httpContext.Response.Body.Write(body, 0, body.Length); + } + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(root + "/basepath/SomePath?SomeQuery"); + Assert.Equal(string.Empty, response); + } + } + [Theory] [InlineData("/", "/", "", "/")] [InlineData("/basepath/", "/basepath", "/basepath", "")] From d8209b6cd465f45ea0b426a648afda45b77ebdad Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 22 Aug 2016 10:53:59 -0700 Subject: [PATCH 377/597] #173 Ignore write failures, fix disconnect notifications. --- src/Microsoft.Net.Http.Server/LogHelper.cs | 14 +- .../NativeInterop/DisconnectListener.cs | 23 +- .../RequestProcessing/ResponseStream.cs | 123 +++--- .../ResponseStreamAsyncResult.cs | 56 ++- .../WebListenerSettings.cs | 6 +- .../ResponseBodyTests.cs | 360 ++++++++++++++++-- .../ResponseSendFileTests.cs | 269 ++++++++++++- 7 files changed, 749 insertions(+), 102 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index 6ec1c67a7b..e96ba71b10 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -53,6 +53,18 @@ namespace Microsoft.Net.Http.Server } } + internal static void LogDebug(ILogger logger, string location, Exception exception) + { + if (logger == null) + { + Debug.WriteLine(exception); + } + else + { + logger.LogDebug(0, exception, location); + } + } + internal static void LogException(ILogger logger, string location, Exception exception) { if (logger == null) @@ -61,7 +73,7 @@ namespace Microsoft.Net.Http.Server } else { - logger.LogError(location, exception); + logger.LogError(0, exception, location); } } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs b/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs index ff45668da9..e96ed834a6 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Concurrent; using System.ComponentModel; +using System.Diagnostics; using System.Threading; using Microsoft.Extensions.Logging; @@ -75,6 +76,7 @@ namespace Microsoft.Net.Http.Server // Create a nativeOverlapped callback so we can register for disconnect callback var cts = new CancellationTokenSource(); + var returnToken = cts.Token; SafeNativeOverlapped nativeOverlapped = null; var boundHandle = _requestQueue.BoundHandle; @@ -97,8 +99,6 @@ namespace Microsoft.Net.Http.Server { LogHelper.LogException(_logger, "CreateDisconnectToken Callback", exception); } - - cts.Dispose(); }, null, null)); @@ -117,19 +117,24 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { - // We got an unknown result so return a None - // TODO: return a canceled token? - return CancellationToken.None; + // We got an unknown result, assume the connection has been closed. + nativeOverlapped.Dispose(); + ConnectionCancellation ignored; + _connectionCancellationTokens.TryRemove(connectionId, out ignored); + LogHelper.LogDebug(_logger, "HttpWaitForDisconnectEx", new Win32Exception((int)statusCode)); + cts.Cancel(); } if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) { - // IO operation completed synchronously - callback won't be called to signal completion. - // TODO: return a canceled token? - return CancellationToken.None; + // IO operation completed synchronously - callback won't be called to signal completion + nativeOverlapped.Dispose(); + ConnectionCancellation ignored; + _connectionCancellationTokens.TryRemove(connectionId, out ignored); + cts.Cancel(); } - return cts.Token; + return returnToken; } private class ConnectionCancellation diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index be0d5ad1a8..cacb354851 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -38,7 +38,8 @@ namespace Microsoft.Net.Http.Server { private RequestContext _requestContext; private long _leftToWrite = long.MinValue; - private bool _closed; + private bool _skipWrites; + private bool _disposed; private bool _inOpaqueMode; // The last write needs special handling to cancel. @@ -60,6 +61,8 @@ namespace Microsoft.Net.Http.Server private ILogger Logger => RequestContext.Server.Logger; + internal bool ThrowWriteExceptions => RequestContext.Server.Settings.ThrowWriteExceptions; + public override bool CanSeek { get @@ -107,7 +110,7 @@ namespace Microsoft.Net.Http.Server // Send headers public override void Flush() { - if (_closed) + if (_disposed) { return; } @@ -119,6 +122,11 @@ namespace Microsoft.Net.Http.Server { Debug.Assert(!(endOfRequest && data.Count > 0), "Data is not supported at the end of the request."); + if (_skipWrites) + { + return; + } + var started = _requestContext.Response.HasStarted; if (data.Count == 0 && started && !endOfRequest) { @@ -170,11 +178,6 @@ namespace Microsoft.Net.Http.Server SafeNativeOverlapped.Zero, IntPtr.Zero); } - - if (_requestContext.Server.Settings.IgnoreWriteExceptions) - { - statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; - } } } finally @@ -186,10 +189,19 @@ namespace Microsoft.Net.Http.Server // Don't throw for disconnects, we were already finished with the response. && (!endOfRequest || (statusCode != ErrorCodes.ERROR_CONNECTION_INVALID && statusCode != ErrorCodes.ERROR_INVALID_PARAMETER))) { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); - LogHelper.LogException(Logger, "Flush", exception); - Abort(); - throw exception; + if (ThrowWriteExceptions) + { + var exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + LogHelper.LogException(Logger, "Flush", exception); + Abort(); + throw exception; + } + else + { + // Abort the request but do not close the stream, let future writes complete silently + LogHelper.LogDebug(Logger, "Flush", $"Ignored write exception: {statusCode}"); + Abort(dispose: false); + } } } @@ -271,7 +283,7 @@ namespace Microsoft.Net.Http.Server public override Task FlushAsync(CancellationToken cancellationToken) { - if (_closed) + if (_disposed) { return Helpers.CompletedTask(); } @@ -281,6 +293,11 @@ namespace Microsoft.Net.Http.Server // Simpler than Flush because it will never be called at the end of the request from Dispose. private unsafe Task FlushInternalAsync(ArraySegment data, CancellationToken cancellationToken) { + if (_skipWrites) + { + return Helpers.CompletedTask(); + } + var started = _requestContext.Response.HasStarted; if (data.Count == 0 && started) { @@ -288,10 +305,10 @@ namespace Microsoft.Net.Http.Server return Helpers.CompletedTask(); } - var cancellationRegistration = default(CancellationTokenRegistration); - if (cancellationToken.CanBeCanceled) + if (cancellationToken.IsCancellationRequested) { - cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); + Abort(ThrowWriteExceptions); + return Helpers.CanceledTask(); } var flags = ComputeLeftToWrite(); @@ -303,7 +320,7 @@ namespace Microsoft.Net.Http.Server UpdateWritenCount((uint)data.Count); uint statusCode = 0; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; - var asyncResult = new ResponseStreamAsyncResult(this, data, chunked, cancellationRegistration); + var asyncResult = new ResponseStreamAsyncResult(this, data, chunked, cancellationToken); uint bytesSent = 0; try { @@ -337,18 +354,25 @@ namespace Microsoft.Net.Http.Server if (statusCode != ErrorCodes.ERROR_SUCCESS && statusCode != ErrorCodes.ERROR_IO_PENDING) { - asyncResult.Dispose(); - if (_requestContext.Server.Settings.IgnoreWriteExceptions && started) + if (cancellationToken.IsCancellationRequested) { - asyncResult.Complete(); + LogHelper.LogDebug(Logger, "FlushAsync", $"Write cancelled with error code: {statusCode}"); + asyncResult.Cancel(ThrowWriteExceptions); } - else + else if (ThrowWriteExceptions) { + asyncResult.Dispose(); Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(Logger, "FlushAsync", exception); Abort(); throw exception; } + else + { + // Abort the request but do not close the stream, let future writes complete silently + LogHelper.LogDebug(Logger, "FlushAsync", $"Ignored write exception: {statusCode}"); + asyncResult.FailSilently(); + } } if (statusCode == ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) @@ -397,9 +421,16 @@ namespace Microsoft.Net.Http.Server #endregion - internal void Abort() + internal void Abort(bool dispose = true) { - _closed = true; + if (dispose) + { + _disposed = true; + } + else + { + _skipWrites = true; + } _requestContext.Abort(); } @@ -476,14 +507,10 @@ namespace Microsoft.Net.Http.Server ((Task)asyncResult).GetAwaiter().GetResult(); } - public override unsafe Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { // Validates for null and bounds. Allows count == 0. var data = new ArraySegment(buffer, offset, count); - if (cancellationToken.IsCancellationRequested) - { - return Helpers.CanceledTask(); - } CheckDisposed(); // TODO: Verbose log parameters @@ -523,33 +550,34 @@ namespace Microsoft.Net.Http.Server internal unsafe Task SendFileAsyncCore(string fileName, long offset, long? count, CancellationToken cancellationToken) { + if (_skipWrites) + { + return Helpers.CompletedTask(); + } + var flags = ComputeLeftToWrite(); if (count == 0 && _leftToWrite != 0) { return Helpers.CompletedTask(); } + if (_leftToWrite >= 0 && count > _leftToWrite) { throw new InvalidOperationException(Resources.Exception_TooMuchWritten); } - // TODO: Verbose log if (cancellationToken.IsCancellationRequested) { + Abort(ThrowWriteExceptions); return Helpers.CanceledTask(); } - - var cancellationRegistration = default(CancellationTokenRegistration); - if (cancellationToken.CanBeCanceled) - { - cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); - } + // TODO: Verbose log uint statusCode; uint bytesSent = 0; var started = _requestContext.Response.HasStarted; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; - ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, fileName, offset, count, chunked, cancellationRegistration); + var asyncResult = new ResponseStreamAsyncResult(this, fileName, offset, count, chunked, cancellationToken); long bytesWritten; if (chunked) @@ -601,18 +629,25 @@ namespace Microsoft.Net.Http.Server if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) { - asyncResult.Dispose(); - if (_requestContext.Server.Settings.IgnoreWriteExceptions && started) + if (cancellationToken.IsCancellationRequested) { - asyncResult.Complete(); + LogHelper.LogDebug(Logger, "SendFileAsync", $"Write cancelled with error code: {statusCode}"); + asyncResult.Cancel(ThrowWriteExceptions); } - else + else if (ThrowWriteExceptions) { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + asyncResult.Dispose(); + var exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); LogHelper.LogException(Logger, "SendFileAsync", exception); Abort(); throw exception; } + else + { + // Abort the request but do not close the stream, let future writes complete silently + LogHelper.LogDebug(Logger, "SendFileAsync", $"Ignored write exception: {statusCode}"); + asyncResult.FailSilently(); + } } if (statusCode == ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) @@ -642,7 +677,7 @@ namespace Microsoft.Net.Http.Server if (_leftToWrite == 0) { // in this case we already passed 0 as the flag, so we don't need to call HttpSendResponseEntityBody() when we Close() - _closed = true; + _disposed = true; } } } @@ -653,11 +688,11 @@ namespace Microsoft.Net.Http.Server { if (disposing) { - if (_closed) + if (_disposed) { return; } - _closed = true; + _disposed = true; FlushInternal(endOfRequest: true); } } @@ -688,7 +723,7 @@ namespace Microsoft.Net.Http.Server private void CheckDisposed() { - if (_closed) + if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 73fa62ff28..49f6ab154b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -41,18 +41,26 @@ namespace Microsoft.Net.Http.Server private ResponseStream _responseStream; private TaskCompletionSource _tcs; private uint _bytesSent; + private CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationRegistration; - internal ResponseStreamAsyncResult(ResponseStream responseStream, CancellationTokenRegistration cancellationRegistration) + internal ResponseStreamAsyncResult(ResponseStream responseStream, CancellationToken cancellationToken) { _responseStream = responseStream; _tcs = new TaskCompletionSource(); + + var cancellationRegistration = default(CancellationTokenRegistration); + if (cancellationToken.CanBeCanceled) + { + cancellationRegistration = _responseStream.RequestContext.RegisterForCancellation(cancellationToken); + } + _cancellationToken = cancellationToken; _cancellationRegistration = cancellationRegistration; } internal ResponseStreamAsyncResult(ResponseStream responseStream, ArraySegment data, bool chunked, - CancellationTokenRegistration cancellationRegistration) - : this(responseStream, cancellationRegistration) + CancellationToken cancellationToken) + : this(responseStream, cancellationToken) { var boundHandle = _responseStream.RequestContext.Server.RequestQueue.BoundHandle; object[] objectsToPin; @@ -107,8 +115,8 @@ namespace Microsoft.Net.Http.Server } internal ResponseStreamAsyncResult(ResponseStream responseStream, string fileName, long offset, - long? count, bool chunked, CancellationTokenRegistration cancellationRegistration) - : this(responseStream, cancellationRegistration) + long? count, bool chunked, CancellationToken cancellationToken) + : this(responseStream, cancellationToken) { var boundHandle = responseStream.RequestContext.Server.RequestQueue.BoundHandle; @@ -260,11 +268,27 @@ namespace Microsoft.Net.Http.Server [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting to callback")] private static void IOCompleted(ResponseStreamAsyncResult asyncResult, uint errorCode, uint numBytes) { + var logger = asyncResult._responseStream.RequestContext.Logger; try { if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - asyncResult.Fail(new IOException(string.Empty, new WebListenerException((int)errorCode))); + if (asyncResult._cancellationToken.IsCancellationRequested) + { + LogHelper.LogDebug(logger, "FlushAsync.IOCompleted", $"Write cancelled with error code: {errorCode}"); + asyncResult.Cancel(asyncResult._responseStream.ThrowWriteExceptions); + } + else if (asyncResult._responseStream.ThrowWriteExceptions) + { + var exception = new IOException(string.Empty, new WebListenerException((int)errorCode)); + LogHelper.LogException(logger, "FlushAsync.IOCompleted", exception); + asyncResult.Fail(exception); + } + else + { + LogHelper.LogDebug(logger, "FlushAsync.IOCompleted", $"Ignored write exception: {errorCode}"); + asyncResult.FailSilently(); + } } else { @@ -285,6 +309,7 @@ namespace Microsoft.Net.Http.Server } catch (Exception e) { + LogHelper.LogException(logger, "FlushAsync.IOCompleted", e); asyncResult.Fail(e); } } @@ -297,15 +322,30 @@ namespace Microsoft.Net.Http.Server internal void Complete() { - _tcs.TrySetResult(null); Dispose(); + _tcs.TrySetResult(null); + } + + internal void FailSilently() + { + Dispose(); + // Abort the request but do not close the stream, let future writes complete silently + _responseStream.Abort(dispose: false); + _tcs.TrySetResult(null); + } + + internal void Cancel(bool dispose) + { + Dispose(); + _responseStream.Abort(dispose); + _tcs.TrySetCanceled(); } internal void Fail(Exception ex) { - _tcs.TrySetException(ex); Dispose(); _responseStream.Abort(); + _tcs.TrySetException(ex); } public object AsyncState diff --git a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs index dd65bc5c3f..c1f8f3c39d 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs @@ -69,13 +69,11 @@ namespace Microsoft.Net.Http.Server /// public TimeoutManager Timeouts { get; } = new TimeoutManager(); - - // TODO: https://github.com/aspnet/WebListener/issues/173 /// /// Gets or Sets if response body writes that fail due to client disconnects should throw exceptions or - /// complete normally. The default is true. + /// complete normally. The default is false. /// - internal bool IgnoreWriteExceptions { get; set; } = true; + public bool ThrowWriteExceptions { get; set; } /// /// Gets or sets the maximum number of requests that will be queued up in Http.Sys. diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 3a2b14fefe..27ad36cabf 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -8,7 +8,6 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server @@ -21,14 +20,14 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Body.Write(new byte[10], 0, 10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; @@ -44,7 +43,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Body.Write(new byte[10], 0, 10); @@ -52,7 +51,7 @@ namespace Microsoft.Net.Http.Server await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -67,7 +66,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["transfeR-Encoding"] = "CHunked"; @@ -76,7 +75,7 @@ namespace Microsoft.Net.Http.Server await stream.WriteAsync(responseBytes, 0, responseBytes.Length); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; @@ -92,11 +91,11 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 30 "; - Stream stream = context.Response.Body; + var stream = context.Response.Body; #if NET451 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); #else @@ -106,7 +105,7 @@ namespace Microsoft.Net.Http.Server await stream.WriteAsync(new byte[10], 0, 10); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable contentLength; @@ -123,7 +122,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; @@ -144,7 +143,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; @@ -161,7 +160,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; @@ -179,7 +178,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 10 "; @@ -204,7 +203,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Body.Write(new byte[10], 0, 0); @@ -212,7 +211,7 @@ namespace Microsoft.Net.Http.Server await context.Response.Body.WriteAsync(new byte[10], 0, 0); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new Version(1, 1), response.Version); IEnumerable ignored; @@ -228,7 +227,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); var cts = new CancellationTokenSource(); @@ -237,7 +236,7 @@ namespace Microsoft.Net.Http.Server await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); } @@ -249,29 +248,30 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromSeconds(1)); + cts.CancelAfter(TimeSpan.FromSeconds(10)); // First write sends headers await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); } } [Fact] - public async Task ResponseBody_FirstWriteAsyncWithCanceledCancellationToken_CancelsButDoesNotAbort() + public async Task ResponseBodyWriteExceptions_FirstWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + server.Settings.ThrowWriteExceptions = true; + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); var cts = new CancellationTokenSource(); @@ -280,20 +280,57 @@ namespace Microsoft.Net.Http.Server var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); - - HttpResponseMessage response = await responseTask; - Assert.Equal(200, (int)response.StatusCode); - Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); +#if NET451 + // .NET 4.5 HttpClient automatically retries a request if it does not get a response. + context = await server.AcceptAsync(); + cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#endif + await Assert.ThrowsAsync(() => responseTask); } } [Fact] - public async Task ResponseBody_SecondWriteAsyncWithCanceledCancellationToken_CancelsButDoesNotAbort() + public async Task ResponseBody_FirstWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + var cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#if NET451 + // .NET 4.5 HttpClient automatically retries a request if it does not get a response. + context = await server.AcceptAsync(); + cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#endif + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task ResponseBodyWriteExceptions_SecondWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); var cts = new CancellationTokenSource(); @@ -304,17 +341,272 @@ namespace Microsoft.Net.Http.Server Assert.True(writeTask.IsCanceled); context.Dispose(); - HttpResponseMessage response = await responseTask; - Assert.Equal(200, (int)response.StatusCode); - Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + await Assert.ThrowsAsync(() => responseTask); } } - private async Task SendRequestAsync(string uri) + [Fact] + public async Task ResponseBody_SecondWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + var cts = new CancellationTokenSource(); + // First write sends headers + await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + cts.Cancel(); + var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); + + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeFirstWrite_WriteThrows() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + var cts = new CancellationTokenSource(); + var responseTask = SendRequestAsync(address, cts.Token); + + var context = await server.AcceptAsync(); + // First write sends headers + cts.Cancel(); + await Assert.ThrowsAsync(() => responseTask); + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + Assert.Throws(() => + { + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 1000; i++) + { + context.Response.Body.Write(new byte[1000], 0, 1000); + } + }); + + Assert.Throws(() => context.Response.Body.Write(new byte[1000], 0, 1000)); + + context.Dispose(); + } + } + + [Fact] + public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeFirstWriteAsync_WriteThrows() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + var cts = new CancellationTokenSource(); + var responseTask = SendRequestAsync(address, cts.Token); + + var context = await server.AcceptAsync(); + + // First write sends headers + cts.Cancel(); + await Assert.ThrowsAsync(() => responseTask); + + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + await Assert.ThrowsAsync(async () => + { + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 1000; i++) + { + await context.Response.Body.WriteAsync(new byte[1000], 0, 1000); + } + }); + + await Assert.ThrowsAsync(() => context.Response.Body.WriteAsync(new byte[1000], 0, 1000)); + + context.Dispose(); + } + } + + [Fact] + public async Task ResponseBody_ClientDisconnectsBeforeFirstWrite_WriteCompletesSilently() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var cts = new CancellationTokenSource(); + var responseTask = SendRequestAsync(address, cts.Token); + + var context = await server.AcceptAsync(); + // First write sends headers + cts.Cancel(); + await Assert.ThrowsAsync(() => responseTask); + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 100; i++) + { + context.Response.Body.Write(new byte[1000], 0, 1000); + } + context.Dispose(); + } + } + + [Fact] + public async Task ResponseBody_ClientDisconnectsBeforeFirstWriteAsync_WriteCompletesSilently() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var cts = new CancellationTokenSource(); + var responseTask = SendRequestAsync(address, cts.Token); + + var context = await server.AcceptAsync(); + // First write sends headers + cts.Cancel(); + await Assert.ThrowsAsync(() => responseTask); + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 100; i++) + { + await context.Response.Body.WriteAsync(new byte[1000], 0, 1000); + } + context.Dispose(); + } + } + + [Fact] + public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWrite_WriteThrows() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + RequestContext context; + using (var client = new HttpClient()) + { + var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); + + context = await server.AcceptAsync(); + // First write sends headers + context.Response.Body.Write(new byte[10], 0, 10); + + var response = await responseTask; + response.EnsureSuccessStatusCode(); + response.Dispose(); + } + + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + Assert.Throws(() => + { + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 100; i++) + { + context.Response.Body.Write(new byte[1000], 0, 1000); + } + }); + context.Dispose(); + } + } + + [Fact] + public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWriteAsync_WriteThrows() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + RequestContext context; + using (var client = new HttpClient()) + { + var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); + + context = await server.AcceptAsync(); + // First write sends headers + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + + var response = await responseTask; + response.EnsureSuccessStatusCode(); + response.Dispose(); + } + + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + await Assert.ThrowsAsync(async () => + { + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 100; i++) + { + await context.Response.Body.WriteAsync(new byte[1000], 0, 1000); + } + }); + context.Dispose(); + } + } + + [Fact] + public async Task ResponseBody_ClientDisconnectsBeforeSecondWrite_WriteCompletesSilently() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + RequestContext context; + using (var client = new HttpClient()) + { + var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); + + context = await server.AcceptAsync(); + // First write sends headers + context.Response.Body.Write(new byte[10], 0, 10); + + var response = await responseTask; + response.EnsureSuccessStatusCode(); + response.Dispose(); + } + + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 10; i++) + { + context.Response.Body.Write(new byte[1000], 0, 1000); + } + context.Dispose(); + } + } + + [Fact] + public async Task ResponseBody_ClientDisconnectsBeforeSecondWriteAsync_WriteCompletesSilently() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + RequestContext context; + using (var client = new HttpClient()) + { + var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); + + context = await server.AcceptAsync(); + // First write sends headers + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + + var response = await responseTask; + response.EnsureSuccessStatusCode(); + response.Dispose(); + } + + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 10; i++) + { + await context.Response.Body.WriteAsync(new byte[1000], 0, 1000); + } + context.Dispose(); + } + } + + private async Task SendRequestAsync(string uri, CancellationToken cancellationToken = new CancellationToken()) { using (HttpClient client = new HttpClient()) { - return await client.GetAsync(uri); + return await client.GetAsync(uri, cancellationToken); } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index b29aa197a4..89073fefbc 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -298,11 +298,276 @@ namespace Microsoft.Net.Http.Server } } - private async Task SendRequestAsync(string uri) + [Fact] + public async Task ResponseSendFile_WithActiveCancellationToken_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + var cts = new CancellationTokenSource(); + // First write sends headers + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFile_WithTimerCancellationToken_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(10)); + // First write sends headers + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + context.Dispose(); + + HttpResponseMessage response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length); + } + } + + [Fact] + public async Task ResponseSendFileWriteExceptions_FirstCallWithCanceledCancellationToken_CancelsAndAborts() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + var cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#if NET451 + // .NET 4.5 HttpClient automatically retries a request if it does not get a response. + context = await server.AcceptAsync(); + cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#endif + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task ResponseSendFile_FirstSendWithCanceledCancellationToken_CancelsAndAborts() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + var cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#if NET451 + // .NET 4.5 HttpClient automatically retries a request if it does not get a response. + context = await server.AcceptAsync(); + cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#endif + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task ResponseSendFileExceptions_SecondSendWithCanceledCancellationToken_CancelsAndAborts() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + var cts = new CancellationTokenSource(); + // First write sends headers + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + cts.Cancel(); + var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); + + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task ResponseSendFile_SecondSendWithCanceledCancellationToken_CancelsAndAborts() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + var cts = new CancellationTokenSource(); + // First write sends headers + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + cts.Cancel(); + var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); + + await Assert.ThrowsAsync(() => responseTask); + } + } + + [Fact] + public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeFirstSend_SendThrows() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + var cts = new CancellationTokenSource(); + var responseTask = SendRequestAsync(address, cts.Token); + + var context = await server.AcceptAsync(); + + // First write sends headers + cts.Cancel(); + await Assert.ThrowsAsync(() => responseTask); + + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + await Assert.ThrowsAsync(async () => + { + // It can take several tries before Send notices the disconnect. + for (int i = 0; i < 1000; i++) + { + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + } + }); + + await Assert.ThrowsAsync(() => + context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None)); + + context.Dispose(); + } + } + + [Fact] + public async Task ResponseSendFile_ClientDisconnectsBeforeFirstSend_SendCompletesSilently() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var cts = new CancellationTokenSource(); + var responseTask = SendRequestAsync(address, cts.Token); + + var context = await server.AcceptAsync(); + // First write sends headers + cts.Cancel(); + await Assert.ThrowsAsync(() => responseTask); + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + // It can take several tries before Send notices the disconnect. + for (int i = 0; i < 100; i++) + { + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + } + context.Dispose(); + } + } + + [Fact] + public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeSecondSend_SendThrows() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + server.Settings.ThrowWriteExceptions = true; + RequestContext context; + using (var client = new HttpClient()) + { + var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); + + context = await server.AcceptAsync(); + // First write sends headers + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + + var response = await responseTask; + response.EnsureSuccessStatusCode(); + response.Dispose(); + } + + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + await Assert.ThrowsAsync(async () => + { + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 100; i++) + { + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + } + }); + context.Dispose(); + } + } + + [Fact] + public async Task ResponseSendFile_ClientDisconnectsBeforeSecondSend_SendCompletesSilently() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + RequestContext context; + using (var client = new HttpClient()) + { + var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); + + context = await server.AcceptAsync(); + // First write sends headers + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + + var response = await responseTask; + response.EnsureSuccessStatusCode(); + response.Dispose(); + } + + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); + // It can take several tries before Write notices the disconnect. + for (int i = 0; i < 10; i++) + { + await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + } + context.Dispose(); + } + } + + private async Task SendRequestAsync(string uri, CancellationToken cancellationToken = new CancellationToken()) { using (HttpClient client = new HttpClient()) { - return await client.GetAsync(uri); + return await client.GetAsync(uri, cancellationToken); } } } From c967382e89d5e8706c9e85ea71b6dcbbd47fd85e Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Mon, 22 Aug 2016 13:22:25 -0700 Subject: [PATCH 378/597] Add Win8 check --- src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs | 6 ++++-- src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs | 3 +-- src/Microsoft.Net.Http.Server/WebSocketHelpers.cs | 3 +-- src/Microsoft.Net.Http.Server/project.json | 4 ++++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index e48bc24d6b..c7a01fb219 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -22,6 +22,7 @@ // ----------------------------------------------------------------------- using System; +using Microsoft.Extensions.Internal; namespace Microsoft.Net.Http.Server { @@ -32,11 +33,12 @@ namespace Microsoft.Net.Http.Server static ComNetOS() { + var win8Version = new Version(6, 2); + #if NETSTANDARD1_3 // TODO: SkipIOCPCallbackOnSuccess doesn't work on Win7. Need a way to detect Win7 vs 8+. - IsWin8orLater = false; + IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version); #else - var win8Version = new Version(6, 2); IsWin8orLater = (Environment.OSVersion.Version >= win8Version); #endif } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index e184ac29c2..43a77a54d1 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -284,8 +284,7 @@ namespace Microsoft.Net.Http.Server public string Scheme => IsHttps ? Constants.HttpsScheme : Constants.HttpScheme; // HTTP.Sys allows you to upgrade anything to opaque unless content-length > 0 or chunked are specified. - // TODO: >= Win8 check https://github.com/aspnet/WebListener/issues/215 - internal bool IsUpgradable => !HasEntityBody; + internal bool IsUpgradable => !HasEntityBody && ComNetOS.IsWin8orLater; public string ContentType => Headers[HttpKnownHeaderNames.ContentType]; diff --git a/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs b/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs index 6d4822ab3e..8ee6466a00 100644 --- a/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs +++ b/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs @@ -67,8 +67,7 @@ namespace Microsoft.Net.Http.Server { get { - // https://github.com/aspnet/WebListener/issues/215 - return true; // TODO: ComNetOS.IsWin8orLater; + return ComNetOS.IsWin8orLater; } } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index e82ad375c9..e23549b60d 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -26,6 +26,10 @@ }, "netstandard1.3": { "dependencies": { + "Microsoft.Extensions.RuntimeEnvironment.Sources": { + "type": "build", + "version": "1.1.0-*" + }, "Microsoft.Win32.Primitives": "4.0.1-*", "System.Diagnostics.Contracts": "4.0.1-*", "System.Diagnostics.Debug": "4.0.11-*", From fe5314ea98bfe0c05d04ea55609190a8a2a0e4f0 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Tue, 23 Aug 2016 09:07:04 -0700 Subject: [PATCH 379/597] Remove old comment --- src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index c7a01fb219..a4fd732d58 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -36,7 +36,6 @@ namespace Microsoft.Net.Http.Server var win8Version = new Version(6, 2); #if NETSTANDARD1_3 - // TODO: SkipIOCPCallbackOnSuccess doesn't work on Win7. Need a way to detect Win7 vs 8+. IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version); #else IsWin8orLater = (Environment.OSVersion.Version >= win8Version); From fc6452235ef8a1ce6190257e613ffd9175ff3345 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 22 Aug 2016 14:25:31 -0700 Subject: [PATCH 380/597] Remove un-used pinvokes --- src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs index 74f4de4788..b50c36a54e 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs @@ -32,9 +32,6 @@ namespace Microsoft.Net.Http.Server [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpReceiveRequestEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, IntPtr pEntityBuffer, uint entityBufferLength, out uint bytesReturned, SafeNativeOverlapped pOverlapped); - [DllImport(HTTPAPI, EntryPoint = "HttpReceiveRequestEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpReceiveRequestEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, void* pEntityBuffer, uint entityBufferLength, out uint bytesReturned, [In] SafeHandle pOverlapped); - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, HTTP_SSL_CLIENT_CERT_INFO* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped); @@ -53,9 +50,6 @@ namespace Microsoft.Net.Http.Server [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpCancelHttpRequest(SafeHandle requestQueueHandle, ulong requestId, IntPtr pOverlapped); - [DllImport(HTTPAPI, EntryPoint = "HttpSendResponseEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSendResponseEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, IntPtr pEntityChunks, out uint pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeHandle pOverlapped, IntPtr pLogData); - [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpWaitForDisconnectEx(SafeHandle requestQueueHandle, ulong connectionId, uint reserved, SafeNativeOverlapped overlapped); From 8fe007e995205bdf25997d277ebb82947c9c545a Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 23 Aug 2016 11:56:37 -0700 Subject: [PATCH 381/597] #237 Make shared CLR code internal --- .../Overlapped/PreAllocatedOverlapped.cs | 2 +- .../Overlapped/ThreadPoolBoundHandle.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs index 7d30b4e248..0ad6b902bf 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs @@ -2,7 +2,7 @@ using System; namespace System.Threading { - public sealed class PreAllocatedOverlapped : IDisposable, IDeferredDisposable + internal sealed class PreAllocatedOverlapped : IDisposable, IDeferredDisposable { internal readonly ThreadPoolBoundHandleOverlapped _overlapped; private DeferredDisposableLifetime _lifetime; diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs index 4356a57f7a..0c2453c0f2 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; namespace System.Threading { - public sealed class ThreadPoolBoundHandle : IDisposable + internal sealed class ThreadPoolBoundHandle : IDisposable { private readonly SafeHandle _handle; private bool _isDisposed; From 26b5d1da2783a7cbb400c3dff6791e6674e1d454 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 23 Aug 2016 11:44:22 -0700 Subject: [PATCH 382/597] #86 Do not fire the ClientDisconnect token for completed responses --- .../RequestProcessing/RequestContext.cs | 20 ++++-- .../RequestProcessing/Response.cs | 2 + .../RequestProcessing/ResponseStream.cs | 2 + .../ServerTests.cs | 62 +++++++++++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 5ad6bbf78d..34b68d7242 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -69,16 +69,24 @@ namespace Microsoft.Net.Http.Server // We need to be able to dispose of the registrations each request to prevent leaks. if (!_disconnectToken.HasValue) { - var connectionDisconnectToken = Server.DisconnectListener.GetTokenForConnection(Request.UConnectionId); - - if (connectionDisconnectToken.CanBeCanceled) + if (_disposed || Response.BodyIsFinished) { - _requestAbortSource = CancellationTokenSource.CreateLinkedTokenSource(connectionDisconnectToken); - _disconnectToken = _requestAbortSource.Token; + // We cannot register for disconnect notifications after the response has finished sending. + _disconnectToken = CancellationToken.None; } else { - _disconnectToken = CancellationToken.None; + var connectionDisconnectToken = Server.DisconnectListener.GetTokenForConnection(Request.UConnectionId); + + if (connectionDisconnectToken.CanBeCanceled) + { + _requestAbortSource = CancellationTokenSource.CreateLinkedTokenSource(connectionDisconnectToken); + _disconnectToken = _requestAbortSource.Token; + } + else + { + _disconnectToken = CancellationToken.None; + } } } return _disconnectToken.Value; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 3ff9af71cd..1c6dc9c2c9 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -115,6 +115,8 @@ namespace Microsoft.Net.Http.Server } } + internal bool BodyIsFinished => _nativeStream?.IsDisposed ?? _responseState >= ResponseState.Closed; + /// /// The authentication challenges that will be added to the response if the status code is 401. /// This must be a subset of the AuthenticationSchemes enabled on the server. diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index cacb354851..b5bfca3915 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -63,6 +63,8 @@ namespace Microsoft.Net.Http.Server internal bool ThrowWriteExceptions => RequestContext.Server.Settings.ThrowWriteExceptions; + internal bool IsDisposed => _disposed; + public override bool CanSeek { get diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 332774d211..21e60cb3aa 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -104,6 +104,68 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task Server_TokenRegisteredAfterClientDisconnects_CallCanceled() + { + var interval = TimeSpan.FromSeconds(1); + var canceled = new ManualResetEvent(false); + + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + using (var client = new HttpClient()) + { + var responseTask = client.GetAsync(address); + + var context = await server.AcceptAsync(); + + client.CancelPendingRequests(); + await Assert.ThrowsAsync(() => responseTask); + + var ct = context.DisconnectToken; + Assert.True(ct.CanBeCanceled, "CanBeCanceled"); + ct.Register(() => canceled.Set()); + Assert.True(ct.WaitHandle.WaitOne(interval)); + Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); + + Assert.True(canceled.WaitOne(interval), "canceled"); + + context.Dispose(); + } + } + } + + [Fact] + public async Task Server_TokenRegisteredAfterResponseSent_Success() + { + var interval = TimeSpan.FromSeconds(1); + var canceled = new ManualResetEvent(false); + + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + using (var client = new HttpClient()) + { + var responseTask = client.GetAsync(address); + + var context = await server.AcceptAsync(); + context.Dispose(); + + var response = await responseTask; + response.EnsureSuccessStatusCode(); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + + var ct = context.DisconnectToken; + Assert.False(ct.CanBeCanceled, "CanBeCanceled"); + ct.Register(() => canceled.Set()); + Assert.False(ct.WaitHandle.WaitOne(interval)); + Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); + + Assert.False(canceled.WaitOne(interval), "canceled"); + } + } + } + [Fact] public async Task Server_Abort_CallCanceled() { From c2a1b8d17fb43f58d24b5c2cb1cde095d247c7e4 Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Wed, 24 Aug 2016 09:41:16 -0700 Subject: [PATCH 383/597] React to NullLogger move --- src/Microsoft.Net.Http.Server/WebListenerSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs index c1f8f3c39d..ce2bd122df 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs @@ -17,7 +17,7 @@ using System; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions.Internal; +using Microsoft.Extensions.Logging.Abstractions; namespace Microsoft.Net.Http.Server { From c2f52db3a5442da54c85a2da3bf65a70639c13a1 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 26 Aug 2016 10:10:09 -0700 Subject: [PATCH 384/597] Reorder SendFileAsync to match Write/FlushAsync --- src/Microsoft.Net.Http.Server/Helpers.cs | 12 ++ .../RequestProcessing/RequestContext.cs | 16 ++- .../RequestProcessing/Response.cs | 15 +-- .../RequestProcessing/ResponseStream.cs | 117 ++++++++++-------- .../ResponseStreamAsyncResult.cs | 37 ++---- src/Microsoft.Net.Http.Server/WebListener.cs | 2 +- .../ResponseSendFileTests.cs | 16 ++- .../ResponseSendFileTests.cs | 59 ++++----- 8 files changed, 143 insertions(+), 131 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/Helpers.cs b/src/Microsoft.Net.Http.Server/Helpers.cs index a117fe2490..6d9aaaba0e 100644 --- a/src/Microsoft.Net.Http.Server/Helpers.cs +++ b/src/Microsoft.Net.Http.Server/Helpers.cs @@ -23,6 +23,7 @@ using System; using System.Runtime.CompilerServices; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -81,6 +82,17 @@ namespace Microsoft.Net.Http.Server return tcs.Task; } + internal static ArraySegment GetChunkHeader(long size) + { + if (size < int.MaxValue) + { + return GetChunkHeader((int)size); + } + + // Greater than 2gb, perf is no longer our concern + return new ArraySegment(Encoding.ASCII.GetBytes(size.ToString("X") + "\r\n")); + } + /// /// A private utility routine to convert an integer to a chunk header, /// which is an ASCII hex number followed by a CRLF.The header is returned diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 34b68d7242..00044c2eed 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -308,12 +308,13 @@ namespace Microsoft.Net.Http.Server // TODO: Verbose log try { - if (_requestAbortSource != null) - { - _requestAbortSource.Dispose(); - } + _requestAbortSource?.Dispose(); Response.Dispose(); } + catch + { + Abort(); + } finally { Request.Dispose(); @@ -334,14 +335,19 @@ namespace Microsoft.Net.Http.Server { _requestAbortSource.Cancel(); } + catch (ObjectDisposedException) + { + } catch (Exception ex) { - LogHelper.LogException(Logger, "Abort", ex); + LogHelper.LogDebug(Logger, "Abort", ex); } _requestAbortSource.Dispose(); } ForceCancelRequest(); Request.Dispose(); + // Only Abort, Response.Dispose() tries a graceful flush + Response.Abort(); } private static void Abort(object state) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 1c6dc9c2c9..07622b5a87 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -109,7 +109,6 @@ namespace Microsoft.Net.Http.Server { get { - CheckDisposed(); EnsureResponseStream(); return _nativeStream; } @@ -245,6 +244,12 @@ namespace Microsoft.Net.Http.Server } } + internal void Abort() + { + // Update state for HasStarted. Do not attempt a graceful Dispose. + _responseState = ResponseState.Closed; + } + // should only be called from RequestContext internal void Dispose() { @@ -685,14 +690,6 @@ namespace Microsoft.Net.Http.Server } } - private void CheckDisposed() - { - if (_responseState >= ResponseState.Closed) - { - throw new ObjectDisposedException(GetType().FullName); - } - } - internal void CancelLastWrite() { _nativeStream?.CancelLastWrite(); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index b5bfca3915..4d23aafa68 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -132,12 +132,13 @@ namespace Microsoft.Net.Http.Server var started = _requestContext.Response.HasStarted; if (data.Count == 0 && started && !endOfRequest) { - // Empty flush + // No data to send and we've already sent the headers return; } + // Make sure all validation is performed before this computes the headers var flags = ComputeLeftToWrite(endOfRequest); - if (!_inOpaqueMode && endOfRequest && _leftToWrite > data.Count) + if (!_inOpaqueMode && endOfRequest && _leftToWrite > 0) { _requestContext.Abort(); // This is logged rather than thrown because it is too late for an exception to be visible in user code. @@ -303,7 +304,7 @@ namespace Microsoft.Net.Http.Server var started = _requestContext.Response.HasStarted; if (data.Count == 0 && started) { - // Empty flush + // No data to send and we've already sent the headers return Helpers.CompletedTask(); } @@ -313,6 +314,7 @@ namespace Microsoft.Net.Http.Server return Helpers.CanceledTask(); } + // Make sure all validation is performed before this computes the headers var flags = ComputeLeftToWrite(); if (_leftToWrite != data.Count) { @@ -464,30 +466,31 @@ namespace Microsoft.Net.Http.Server public override void Write(byte[] buffer, int offset, int count) { // Validates for null and bounds. Allows count == 0. + // TODO: Verbose log parameters var data = new ArraySegment(buffer, offset, count); CheckDisposed(); - // TODO: Verbose log parameters - var contentLength = _requestContext.Response.ContentLength; - if (contentLength.HasValue && !_requestContext.Response.HasComputedHeaders && contentLength.Value <= data.Count) - { - if (contentLength.Value < data.Count) - { - throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); - } - } - // The last write in a response that has already started, flush immediately - else if (_requestContext.Response.HasComputedHeaders && _leftToWrite >= 0 && _leftToWrite <= data.Count) - { - if (_leftToWrite < data.Count) - { - throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); - } - } + CheckWriteCount(count); FlushInternal(endOfRequest: false, data: data); } + private void CheckWriteCount(long? count) + { + var contentLength = _requestContext.Response.ContentLength; + // First write with more bytes written than the entire content-length + if (!_requestContext.Response.HasComputedHeaders && contentLength < count) + { + throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); + } + // A write in a response that has already started where the count exceeds the remainder of the content-length + else if (_requestContext.Response.HasComputedHeaders && _requestContext.Response.BoundaryType == BoundaryType.ContentLength + && _leftToWrite < count) + { + throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); + } + } + #if NETSTANDARD1_3 public IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) #else @@ -512,26 +515,11 @@ namespace Microsoft.Net.Http.Server public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { // Validates for null and bounds. Allows count == 0. + // TODO: Verbose log parameters var data = new ArraySegment(buffer, offset, count); CheckDisposed(); - // TODO: Verbose log parameters - var contentLength = _requestContext.Response.ContentLength; - if (contentLength.HasValue && !_requestContext.Response.HasComputedHeaders && contentLength.Value <= data.Count) - { - if (contentLength.Value < data.Count) - { - throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); - } - } - // The last write in a response that has already started, flush immediately - else if (_requestContext.Response.HasComputedHeaders && _leftToWrite > 0 && _leftToWrite <= data.Count) - { - if (_leftToWrite < data.Count) - { - throw new InvalidOperationException("More bytes written than specified in the Content-Length header."); - } - } + CheckWriteCount(count); return FlushInternalAsync(data, cancellationToken); } @@ -540,12 +528,15 @@ namespace Microsoft.Net.Http.Server { // It's too expensive to validate the file attributes before opening the file. Open the file and then check the lengths. // This all happens inside of ResponseStreamAsyncResult. + // TODO: Verbose log parameters if (string.IsNullOrWhiteSpace(fileName)) { throw new ArgumentNullException("fileName"); } CheckDisposed(); + CheckWriteCount(count); + // We can't mix await and unsafe so separate the unsafe code into another method. await SendFileAsyncCore(fileName, offset, count, cancellationToken); } @@ -557,43 +548,65 @@ namespace Microsoft.Net.Http.Server return Helpers.CompletedTask(); } - var flags = ComputeLeftToWrite(); - if (count == 0 && _leftToWrite != 0) + var started = _requestContext.Response.HasStarted; + if (count == 0 && started) { + // No data to send and we've already sent the headers return Helpers.CompletedTask(); } - if (_leftToWrite >= 0 && count > _leftToWrite) - { - throw new InvalidOperationException(Resources.Exception_TooMuchWritten); - } - if (cancellationToken.IsCancellationRequested) { Abort(ThrowWriteExceptions); return Helpers.CanceledTask(); } - // TODO: Verbose log + // We are setting buffer size to 1 to prevent FileStream from allocating it's internal buffer + // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. + var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize: 1, + options: FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive. + + try + { + var length = fileStream.Length; // Expensive, only do it once + if (!count.HasValue) + { + count = length - offset; + } + if (offset < 0 || offset > length) + { + throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty); + } + if (count < 0 || count > length - offset) + { + throw new ArgumentOutOfRangeException(nameof(count), count, string.Empty); + } + + CheckWriteCount(count); + } + catch + { + fileStream.Dispose(); + throw; + } + + // Make sure all validation is performed before this computes the headers + var flags = ComputeLeftToWrite(); uint statusCode; uint bytesSent = 0; - var started = _requestContext.Response.HasStarted; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; - var asyncResult = new ResponseStreamAsyncResult(this, fileName, offset, count, chunked, cancellationToken); + var asyncResult = new ResponseStreamAsyncResult(this, fileStream, offset, count.Value, chunked, cancellationToken); long bytesWritten; if (chunked) { bytesWritten = 0; } - else if (count.HasValue) + else { bytesWritten = count.Value; } - else - { - bytesWritten = asyncResult.FileLength - offset; - } + // Update _leftToWrite now so we can queue up additional calls to SendFileAsync. flags |= _leftToWrite == bytesWritten ? HttpApi.HTTP_FLAGS.NONE : HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; UpdateWritenCount((uint)bytesWritten); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 49f6ab154b..451a327025 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -114,33 +114,15 @@ namespace Microsoft.Net.Http.Server } } - internal ResponseStreamAsyncResult(ResponseStream responseStream, string fileName, long offset, - long? count, bool chunked, CancellationToken cancellationToken) + internal ResponseStreamAsyncResult(ResponseStream responseStream, FileStream fileStream, long offset, + long count, bool chunked, CancellationToken cancellationToken) : this(responseStream, cancellationToken) { var boundHandle = responseStream.RequestContext.Server.RequestQueue.BoundHandle; - int bufferSize = 1024 * 64; // TODO: Validate buffer size choice. -#if NETSTANDARD1_3 - _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive. -#else - // It's too expensive to validate anything before opening the file. Open the file and then check the lengths. - _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, - FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive. -#endif - long length = _fileStream.Length; // Expensive - if (offset < 0 || offset > length) - { - _fileStream.Dispose(); - throw new ArgumentOutOfRangeException("offset", offset, string.Empty); - } - if (count.HasValue && (count < 0 || count > length - offset)) - { - _fileStream.Dispose(); - throw new ArgumentOutOfRangeException("count", count, string.Empty); - } + _fileStream = fileStream; - if (count == 0 || (!count.HasValue && _fileStream.Length == 0)) + if (count == 0) { _dataChunks = null; _overlapped = new SafeNativeOverlapped(boundHandle, @@ -156,14 +138,14 @@ namespace Microsoft.Net.Http.Server var chunkHeaderBuffer = new ArraySegment(); if (chunked) { - chunkHeaderBuffer = Helpers.GetChunkHeader((int)(count ?? _fileStream.Length - offset)); + chunkHeaderBuffer = Helpers.GetChunkHeader(count); _dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; _dataChunks[0].fromMemory.BufferLength = (uint)chunkHeaderBuffer.Count; objectsToPin[0] = chunkHeaderBuffer.Array; _dataChunks[1].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[1].fromFile.offset = (ulong)offset; - _dataChunks[1].fromFile.count = (ulong)(count ?? -1); + _dataChunks[1].fromFile.count = (ulong)count; _dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); // Nothing to pin for the file handle. @@ -175,7 +157,7 @@ namespace Microsoft.Net.Http.Server { _dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[0].fromFile.offset = (ulong)offset; - _dataChunks[0].fromFile.count = (ulong)(count ?? -1); + _dataChunks[0].fromFile.count = (ulong)count; _dataChunks[0].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); } @@ -248,11 +230,6 @@ namespace Microsoft.Net.Http.Server } } - internal long FileLength - { - get { return _fileStream == null ? 0 : _fileStream.Length; } - } - internal bool EndCalled { get; set; } internal void IOCompleted(uint errorCode) diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index f7dde384fc..cb72439299 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -40,7 +40,7 @@ namespace Microsoft.Net.Http.Server // returned from HttpReceiveClientCertificate when using the // FileCompletionNotificationModes.SkipCompletionPortOnSuccess flag. // This bug was only hit when the buffer passed into HttpReceiveClientCertificate - // (1500 bytes initially) is tool small for the certificate. + // (1500 bytes initially) is too small for the certificate. // Due to this bug in downlevel operating systems the FileCompletionNotificationModes.SkipCompletionPortOnSuccess // flag is only used on Win8 and later. internal static readonly bool SkipIOCPCallbackOnSuccess = ComNetOS.IsWin8orLater; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 7cc9269f12..62616c6a6e 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -221,12 +221,14 @@ namespace Microsoft.AspNetCore.Server.WebListener using (Utilities.CreateHttpServer(out address, async httpContext => { var sendFile = httpContext.Features.Get(); - await sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None); + await Assert.ThrowsAsync(() => + sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None)); completed = true; })) { - await Assert.ThrowsAsync(() => SendRequestAsync(address)); - Assert.False(completed); + var response = await SendRequestAsync(address); + response.EnsureSuccessStatusCode(); + Assert.True(completed); } } @@ -238,12 +240,14 @@ namespace Microsoft.AspNetCore.Server.WebListener using (Utilities.CreateHttpServer(out address, async httpContext => { var sendFile = httpContext.Features.Get(); - await sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None); + await Assert.ThrowsAsync(() => + sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None)); completed = true; })) { - await Assert.ThrowsAsync(() => SendRequestAsync(address)); - Assert.False(completed); + var response = await SendRequestAsync(address); + response.EnsureSuccessStatusCode(); + Assert.True(completed); } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index 89073fefbc..a34729f912 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -30,14 +30,15 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await Assert.ThrowsAsync(() => context.Response.SendFileAsync("Missing.txt", 0, null, CancellationToken.None)); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; + response.EnsureSuccessStatusCode(); } } @@ -47,13 +48,13 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable ignored; Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); @@ -68,13 +69,13 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await context.Response.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable ignored; Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); @@ -89,13 +90,13 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -110,14 +111,14 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -132,13 +133,13 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -153,14 +154,15 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await Assert.ThrowsAsync( () => context.Response.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None)); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; + response.EnsureSuccessStatusCode(); } } @@ -170,14 +172,15 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await Assert.ThrowsAsync( () => context.Response.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None)); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; + response.EnsureSuccessStatusCode(); } } @@ -187,13 +190,13 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -212,7 +215,7 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); await context.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None); @@ -221,7 +224,7 @@ namespace Microsoft.Net.Http.Server context.Dispose(); File.Delete(emptyFilePath); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -236,13 +239,13 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = FileLength.ToString(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -258,14 +261,14 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = "10"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -281,14 +284,14 @@ namespace Microsoft.Net.Http.Server string address; using (var server = Utilities.CreateHttpServer(out address)) { - Task responseTask = SendRequestAsync(address); + var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = "0"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); IEnumerable contentLength; Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); @@ -313,7 +316,7 @@ namespace Microsoft.Net.Http.Server await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length); } @@ -335,7 +338,7 @@ namespace Microsoft.Net.Http.Server await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); context.Dispose(); - HttpResponseMessage response = await responseTask; + var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length); } From 3d1dbbaae5486393fe3c4982693d59964221f33a Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 26 Aug 2016 16:01:20 -0700 Subject: [PATCH 385/597] #183 Set empty paths for OPTIONS * requests --- .../RequestProcessing/Request.cs | 14 +++++++++++--- .../RequestTests.cs | 19 +++++++++++++++++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 43a77a54d1..924b7eef2c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -64,6 +64,10 @@ namespace Microsoft.Net.Http.Server SslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure : memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : SslStatus.ClientCert; + + KnownMethod = memoryBlob.RequestBlob->Verb; + Method = HttpApi.GetVerb(memoryBlob.RequestBlob); + if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0) { RawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); @@ -89,8 +93,14 @@ namespace Microsoft.Net.Http.Server var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)memoryBlob.RequestBlob->UrlContext); var originalPath = RequestUriBuilder.GetRequestPath(RawUrl, cookedUrlPath, RequestContext.Logger); + // 'OPTIONS * HTTP/1.1' + if (KnownMethod == HttpApi.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal)) + { + PathBase = string.Empty; + Path = string.Empty; + } // These paths are both unescaped already. - if (originalPath.Length == prefix.Path.Length - 1) + else if (originalPath.Length == prefix.Path.Length - 1) { // They matched exactly except for the trailing slash. PathBase = originalPath; @@ -119,8 +129,6 @@ namespace Microsoft.Net.Http.Server ProtocolVersion = new Version(major, minor); } - KnownMethod = memoryBlob.RequestBlob->Verb; - Method = HttpApi.GetVerb(memoryBlob.RequestBlob); Headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); var requestV2 = (HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index 31e5e850bf..fa28c81d5b 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -111,6 +111,21 @@ namespace Microsoft.Net.Http.Server } } + [Fact] + public async Task Request_OptionsStar_EmptyPath() + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) + { + var responseTask = SendSocketRequestAsync(root, "*", "OPTIONS"); + var context = await server.AcceptAsync(); + Assert.Equal("", context.Request.PathBase); + Assert.Equal("", context.Request.Path); + Assert.Equal("*", context.Request.RawUrl); + context.Dispose(); + } + } + [Theory] // The test server defines these prefixes: "/", "/11", "/2/3", "/2", "/11/2" [InlineData("/", "", "/")] @@ -163,11 +178,11 @@ namespace Microsoft.Net.Http.Server } } - private async Task SendSocketRequestAsync(string address, string path) + private async Task SendSocketRequestAsync(string address, string path, string method = "GET") { var uri = new Uri(address); StringBuilder builder = new StringBuilder(); - builder.AppendLine("GET " + path + " HTTP/1.1"); + builder.AppendLine($"{method} {path} HTTP/1.1"); builder.AppendLine("Connection: close"); builder.Append("HOST: "); builder.AppendLine(uri.Authority); From b31ec7d7a723d111ba565f4fd8d6836c5ad26961 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 31 Aug 2016 14:19:56 -0700 Subject: [PATCH 386/597] #204 Consolidate unsafe buffer access into NativeRequestContext --- .../AsyncAcceptContext.cs | 14 +- .../AuthenticationManager.cs | 46 -- .../NativeInterop/CookedUrl.cs | 75 +++ .../NativeInterop/HttpApi.cs | 200 -------- .../RequestProcessing/NativeRequestContext.cs | 431 +++++++++++++----- .../RequestProcessing/Request.cs | 99 +--- .../RequestProcessing/RequestHeaders.cs | 6 +- .../RequestProcessing/RequestStream.cs | 10 +- src/Microsoft.Net.Http.Server/WebListener.cs | 9 +- .../ResponseCachingTests.cs | 4 +- 10 files changed, 442 insertions(+), 452 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs diff --git a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs index d42a66e605..58a5f7f186 100644 --- a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs @@ -108,13 +108,13 @@ namespace Microsoft.Net.Http.Server } else { - asyncResult._nativeRequestContext.Reset(0, 0); + asyncResult._nativeRequestContext.Reset(); } } } else { - asyncResult._nativeRequestContext.Reset(asyncResult._nativeRequestContext.RequestBlob->RequestId, numBytes); + asyncResult._nativeRequestContext.Reset(asyncResult._nativeRequestContext.RequestId, numBytes); } // We need to issue a new request, either because auth failed, or because our buffer was too small the first time. @@ -166,26 +166,26 @@ namespace Microsoft.Net.Http.Server uint bytesTransferred = 0; statusCode = HttpApi.HttpReceiveHttpRequest( Server.RequestQueue.Handle, - _nativeRequestContext.RequestBlob->RequestId, + _nativeRequestContext.RequestId, (uint)HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, - _nativeRequestContext.RequestBlob, + _nativeRequestContext.NativeRequest, _nativeRequestContext.Size, &bytesTransferred, _nativeRequestContext.NativeOverlapped); - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER && _nativeRequestContext.RequestBlob->RequestId != 0) + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER && _nativeRequestContext.RequestId != 0) { // we might get this if somebody stole our RequestId, // set RequestId to 0 and start all over again with the buffer we just allocated // BUGBUG: how can someone steal our request ID? seems really bad and in need of fix. - _nativeRequestContext.RequestBlob->RequestId = 0; + _nativeRequestContext.RequestId = 0; retry = true; } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) { // the buffer was not big enough to fit the headers, we need // to read the RequestId returned, allocate a new buffer of the required size - _nativeRequestContext.Reset(_nativeRequestContext.RequestBlob->RequestId, bytesTransferred); + _nativeRequestContext.Reset(_nativeRequestContext.RequestId, bytesTransferred); retry = true; } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index fb8766996a..14153b285b 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -152,51 +152,5 @@ namespace Microsoft.Net.Http.Server = StringValues.Concat(context.Response.Headers[HttpKnownHeaderNames.WWWAuthenticate], challenges.ToArray()); } } - - internal static unsafe bool CheckAuthenticated(HttpApi.HTTP_REQUEST_INFO* requestInfo) - { - if (requestInfo != null - && requestInfo->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth - && requestInfo->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) - { - return true; - } - return false; - } - - internal static unsafe ClaimsPrincipal GetUser(HttpApi.HTTP_REQUEST_INFO* requestInfo, int infoCount) - { - for (int i = 0; i < infoCount; i++) - { - var info = &requestInfo[i]; - if (requestInfo != null - && info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth - && info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) - { - return new WindowsPrincipal(new WindowsIdentity(info->pInfo->AccessToken, - GetAuthTypeFromRequest(info->pInfo->AuthType).ToString())); - } - } - return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated - } - - private static AuthenticationSchemes GetAuthTypeFromRequest(HttpApi.HTTP_REQUEST_AUTH_TYPE input) - { - switch (input) - { - case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic: - return AuthenticationSchemes.Basic; - // case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest: - // return AuthenticationSchemes.Digest; - case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM: - return AuthenticationSchemes.NTLM; - case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate: - return AuthenticationSchemes.Negotiate; - case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos: - return AuthenticationSchemes.Kerberos; - default: - throw new NotImplementedException(input.ToString()); - } - } } } diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs b/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs new file mode 100644 index 0000000000..ed702b7406 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Net.Http.Server +{ + // Note this type should only be used while the request buffer remains pinned + internal class CookedUrl + { + private readonly HttpApi.HTTP_COOKED_URL _nativeCookedUrl; + + internal CookedUrl(HttpApi.HTTP_COOKED_URL nativeCookedUrl) + { + _nativeCookedUrl = nativeCookedUrl; + } + + internal unsafe string GetFullUrl() + { + if (_nativeCookedUrl.pFullUrl != null && _nativeCookedUrl.FullUrlLength > 0) + { + return Marshal.PtrToStringUni((IntPtr)_nativeCookedUrl.pFullUrl, _nativeCookedUrl.FullUrlLength / 2); + } + return null; + } + + internal unsafe string GetHost() + { + if (_nativeCookedUrl.pHost != null && _nativeCookedUrl.HostLength > 0) + { + return Marshal.PtrToStringUni((IntPtr)_nativeCookedUrl.pHost, _nativeCookedUrl.HostLength / 2); + } + return null; + } + + internal unsafe string GetAbsPath() + { + if (_nativeCookedUrl.pAbsPath != null && _nativeCookedUrl.AbsPathLength > 0) + { + return Marshal.PtrToStringUni((IntPtr)_nativeCookedUrl.pAbsPath, _nativeCookedUrl.AbsPathLength / 2); + } + return null; + } + + internal unsafe string GetQueryString() + { + if (_nativeCookedUrl.pQueryString != null && _nativeCookedUrl.QueryStringLength > 0) + { + return Marshal.PtrToStringUni((IntPtr)_nativeCookedUrl.pQueryString, _nativeCookedUrl.QueryStringLength / 2); + } + return null; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs index b50c36a54e..10c736af80 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs @@ -868,205 +868,5 @@ namespace Microsoft.Net.Http.Server return supported; } } - - // Server API - - internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob, - int requestOffset, IntPtr originalAddress) - { - // Return value. - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - long fixup = pMemoryBlob - (byte*)originalAddress; - int index; - - // unknown headers - if (request->Headers.UnknownHeaderCount != 0) - { - HTTP_UNKNOWN_HEADER* pUnknownHeader = (HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders); - for (index = 0; index < request->Headers.UnknownHeaderCount; index++) - { - // For unknown headers, when header value is empty, RawValueLength will be 0 and - // pRawValue will be null. - if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) - { - string headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength); - string headerValue; - if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) - { - headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength); - } - else - { - headerValue = string.Empty; - } - // Note that Http.Sys currently collapses all headers of the same name to a single coma seperated string, - // so we can just call Set. - unknownHeaders[headerName] = headerValue; - } - pUnknownHeader++; - } - } - } - } - - private static string GetKnownHeader(HTTP_REQUEST* request, long fixup, int headerIndex) - { - string header = null; - - HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; - // For known headers, when header value is empty, RawValueLength will be 0 and - // pRawValue will point to empty string ("\0") - if (pKnownHeader->pRawValue != null) - { - header = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength); - } - - return header; - } - - internal static string GetKnownHeader(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, int headerIndex) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - return GetKnownHeader( - (HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress, headerIndex); - } - } - - // This requires the HTTP_REQUEST to still be pinned in its original location. - internal static unsafe string GetVerb(HTTP_REQUEST* request) - { - string verb = null; - - if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnknown && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) - { - verb = HttpVerbs[(int)request->Verb]; - } - else if (request->Verb == HTTP_VERB.HttpVerbUnknown && request->pUnknownVerb != null) - { - verb = HeaderEncoding.GetString(request->pUnknownVerb, request->UnknownVerbLength); - } - - return verb; - } - - internal static uint GetChunks(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, - ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) - { - // Return value. - uint dataRead = 0; - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - long fixup = pMemoryBlob - (byte*)originalAddress; - - if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) - { - HTTP_DATA_CHUNK* pDataChunk = (HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); - - fixed (byte* pReadBuffer = buffer) - { - byte* pTo = &pReadBuffer[offset]; - - while (dataChunkIndex < request->EntityChunkCount && dataRead < size) - { - if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength) - { - dataChunkOffset = 0; - dataChunkIndex++; - pDataChunk++; - } - else - { - byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup; - - uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset; - if (bytesToRead > (uint)size) - { - bytesToRead = (uint)size; - } - for (uint i = 0; i < bytesToRead; i++) - { - *(pTo++) = *(pFrom++); - } - dataRead += bytesToRead; - dataChunkOffset += bytesToRead; - } - } - } - } - // we're finished. - if (dataChunkIndex == request->EntityChunkCount) - { - dataChunkIndex = -1; - } - } - - return dataRead; - } - - internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pRemoteAddress); - } - } - - internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset); - return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pLocalAddress); - } - } - - internal static SocketAddress GetEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, byte* source) - { - fixed (byte* pMemoryBlob = memoryBlob) - { - IntPtr address = source != null ? - (IntPtr)(pMemoryBlob + requestOffset - (byte*)originalAddress + source) : IntPtr.Zero; - return CopyOutAddress(address); - } - } - - private static SocketAddress CopyOutAddress(IntPtr address) - { - if (address != IntPtr.Zero) - { - ushort addressFamily = *((ushort*)address); - if (addressFamily == (ushort)AddressFamily.InterNetwork) - { - SocketAddress v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize); - fixed (byte* pBuffer = v4address.Buffer) - { - for (int index = 2; index < SocketAddress.IPv4AddressSize; index++) - { - pBuffer[index] = ((byte*)address)[index]; - } - } - return v4address; - } - if (addressFamily == (ushort)AddressFamily.InterNetworkV6) - { - SocketAddress v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize); - fixed (byte* pBuffer = v6address.Buffer) - { - for (int index = 2; index < SocketAddress.IPv6AddressSize; index++) - { - pBuffer[index] = ((byte*)address)[index]; - } - } - return v6address; - } - } - - return null; - } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 5072342c42..32a93e8ae6 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -22,9 +22,12 @@ //------------------------------------------------------------------------------ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; -using System.Threading; +using System.Security.Claims; +using System.Security.Principal; +using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Server { @@ -32,8 +35,8 @@ namespace Microsoft.Net.Http.Server { private const int DefaultBufferSize = 4096; private const int AlignmentPadding = 8; - private HttpApi.HTTP_REQUEST* _memoryBlob; - private IntPtr _originalBlobAddress; + private HttpApi.HTTP_REQUEST* _nativeRequest; + private IntPtr _originalBufferAddress; private byte[] _backingBuffer; private int _bufferAlignment; private SafeNativeOverlapped _nativeOverlapped; @@ -42,125 +45,73 @@ namespace Microsoft.Net.Http.Server internal NativeRequestContext(AsyncAcceptContext result) { _acceptResult = result; - HttpApi.HTTP_REQUEST* requestBlob = Allocate(0); - if (requestBlob == null) - { - GC.SuppressFinalize(this); - } - else - { - _memoryBlob = requestBlob; - } + AllocateNativeRequest(); } - internal SafeNativeOverlapped NativeOverlapped + internal SafeNativeOverlapped NativeOverlapped => _nativeOverlapped; + + internal HttpApi.HTTP_REQUEST* NativeRequest { get { - return _nativeOverlapped; + Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins()."); + return _nativeRequest; } } - internal HttpApi.HTTP_REQUEST* RequestBlob + private HttpApi.HTTP_REQUEST_V2* NativeRequestV2 { get { - Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestBlob requested after ReleasePins()."); - return _memoryBlob; + Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins()."); + return (HttpApi.HTTP_REQUEST_V2*)_nativeRequest; } } - internal byte[] RequestBuffer + internal ulong RequestId + { + get { return NativeRequest->RequestId; } + set { NativeRequest->RequestId = value; } + } + + internal ulong ConnectionId => NativeRequest->ConnectionId; + + internal HttpApi.HTTP_VERB VerbId => NativeRequest->Verb; + + internal ulong UrlContext => NativeRequest->UrlContext; + + internal ushort UnknownHeaderCount => NativeRequest->Headers.UnknownHeaderCount; + + internal SslStatus SslStatus { get { - return _backingBuffer; + return NativeRequest->pSslInfo == null ? SslStatus.Insecure : + NativeRequest->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : + SslStatus.ClientCert; } } internal uint Size { - get - { - return (uint)_backingBuffer.Length - AlignmentPadding; - } - } - - internal int BufferAlignment - { - get - { - return _bufferAlignment; - } - } - - internal IntPtr OriginalBlobAddress - { - get - { - HttpApi.HTTP_REQUEST* blob = _memoryBlob; - return blob == null ? _originalBlobAddress : (IntPtr)blob; - } + get { return (uint)_backingBuffer.Length - AlignmentPadding; } } // ReleasePins() should be called exactly once. It must be called before Dispose() is called, which means it must be called // before an object (Request) which closes the RequestContext on demand is returned to the application. internal void ReleasePins() { - Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice."); - _originalBlobAddress = (IntPtr)_memoryBlob; - UnsetBlob(); - OnReleasePins(); - } - - private void OnReleasePins() - { - if (_nativeOverlapped != null) - { - SafeNativeOverlapped nativeOverlapped = _nativeOverlapped; - _nativeOverlapped = null; - nativeOverlapped.Dispose(); - } + Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice."); + _originalBufferAddress = (IntPtr)_nativeRequest; + _nativeRequest = null; + _nativeOverlapped?.Dispose(); + _nativeOverlapped = null; } public void Dispose() { - Debug.Assert(_memoryBlob == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins()."); - Dispose(true); - } - - protected void Dispose(bool disposing) - { - if (_nativeOverlapped != null) - { - Debug.Assert(!disposing, "AsyncRequestContext::Dispose()|Must call ReleasePins() before calling Dispose()."); - _nativeOverlapped.Dispose(); - } - } - - private void SetBlob(HttpApi.HTTP_REQUEST* requestBlob) - { - Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::Dispose()|SetBlob() called after ReleasePins()."); - if (requestBlob == null) - { - UnsetBlob(); - return; - } - - if (_memoryBlob == null) - { - GC.ReRegisterForFinalize(this); - } - _memoryBlob = requestBlob; - } - - private void UnsetBlob() - { - if (_memoryBlob != null) - { - GC.SuppressFinalize(this); - } - _memoryBlob = null; + Debug.Assert(_nativeRequest == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins()."); + _nativeOverlapped?.Dispose(); } private void SetBuffer(int size) @@ -170,34 +121,306 @@ namespace Microsoft.Net.Http.Server _backingBuffer = new byte[size + AlignmentPadding]; } - private HttpApi.HTTP_REQUEST* Allocate(uint size) + private void AllocateNativeRequest(uint? size = null) { // We can't reuse overlapped objects - if (_nativeOverlapped != null) - { - SafeNativeOverlapped nativeOverlapped = _nativeOverlapped; - _nativeOverlapped = null; - nativeOverlapped.Dispose(); - } + _nativeOverlapped?.Dispose(); - uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size; + uint newSize = size.HasValue ? size.Value : _backingBuffer == null ? DefaultBufferSize : Size; SetBuffer(checked((int)newSize)); var boundHandle = _acceptResult.Server.RequestQueue.BoundHandle; _nativeOverlapped = new SafeNativeOverlapped(boundHandle, - boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer)); + boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, _backingBuffer)); // HttpReceiveHttpRequest expects the request pointer to be 8-byte-aligned or it fails. On ARM // CLR creates buffers that are 4-byte-aligned so we need force 8-byte alignment. - var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); + var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07); - return (HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment); + _nativeRequest = (HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment); } - internal void Reset(ulong requestId, uint size) + internal void Reset(ulong requestId = 0, uint? size = null) { - SetBlob(Allocate(size)); - RequestBlob->RequestId = requestId; + Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::Dispose()|SetNativeRequest() called after ReleasePins()."); + AllocateNativeRequest(size); + RequestId = requestId; + } + + // These methods require the HTTP_REQUEST to still be pinned in its original location. + + internal string GetVerb() + { + var verb = NativeRequest->Verb; + if (verb > HttpApi.HTTP_VERB.HttpVerbUnknown && verb < HttpApi.HTTP_VERB.HttpVerbMaximum) + { + return HttpApi.HttpVerbs[(int)verb]; + } + else if (verb == HttpApi.HTTP_VERB.HttpVerbUnknown && NativeRequest->pUnknownVerb != null) + { + return HeaderEncoding.GetString(NativeRequest->pUnknownVerb, NativeRequest->UnknownVerbLength); + } + + return null; + } + + internal string GetRawUrl() + { + if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0) + { + return Marshal.PtrToStringAnsi((IntPtr)NativeRequest->pRawUrl, NativeRequest->RawUrlLength); + } + return null; + } + + internal CookedUrl GetCookedUrl() + { + return new CookedUrl(NativeRequest->CookedUrl); + } + + internal Version GetVersion() + { + var major = NativeRequest->Version.MajorVersion; + var minor = NativeRequest->Version.MinorVersion; + if (major == 1 && minor == 1) + { + return Constants.V1_1; + } + else if (major == 1 && minor == 0) + { + return Constants.V1_0; + } + return new Version(major, minor); + } + + internal bool CheckAuthenticated() + { + var requestInfo = NativeRequestV2->pRequestInfo; + var infoCount = NativeRequestV2->RequestInfoCount; + + for (int i = 0; i < infoCount; i++) + { + var info = &requestInfo[i]; + if (info != null + && info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + { + return true; + } + } + return false; + } + + internal ClaimsPrincipal GetUser() + { + var requestInfo = NativeRequestV2->pRequestInfo; + var infoCount = NativeRequestV2->RequestInfoCount; + + for (int i = 0; i < infoCount; i++) + { + var info = &requestInfo[i]; + if (info != null + && info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + { + return new WindowsPrincipal(new WindowsIdentity(info->pInfo->AccessToken, + GetAuthTypeFromRequest(info->pInfo->AuthType).ToString())); + } + } + return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated + } + + private static AuthenticationSchemes GetAuthTypeFromRequest(HttpApi.HTTP_REQUEST_AUTH_TYPE input) + { + switch (input) + { + case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic: + return AuthenticationSchemes.Basic; + // case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest: + // return AuthenticationSchemes.Digest; + case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM: + return AuthenticationSchemes.NTLM; + case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate: + return AuthenticationSchemes.Negotiate; + case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos: + return AuthenticationSchemes.Kerberos; + default: + throw new NotImplementedException(input.ToString()); + } + } + + // These methods are for accessing the request structure after it has been unpinned. They need to adjust addresses + // in case GC has moved the original object. + + internal string GetKnownHeader(HttpSysRequestHeader header) + { + fixed (byte* pMemoryBlob = _backingBuffer) + { + var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); + long fixup = pMemoryBlob - (byte*)_originalBufferAddress; + int headerIndex = (int)header; + string value = null; + + HttpApi.HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; + // For known headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will point to empty string ("\0") + if (pKnownHeader->pRawValue != null) + { + value = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength); + } + + return value; + } + } + + internal void GetUnknownHeaders(IDictionary unknownHeaders) + { + // Return value. + fixed (byte* pMemoryBlob = _backingBuffer) + { + var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); + long fixup = pMemoryBlob - (byte*)_originalBufferAddress; + int index; + + // unknown headers + if (request->Headers.UnknownHeaderCount != 0) + { + var pUnknownHeader = (HttpApi.HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders); + for (index = 0; index < request->Headers.UnknownHeaderCount; index++) + { + // For unknown headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will be null. + if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) + { + var headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength); + string headerValue; + if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) + { + headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength); + } + else + { + headerValue = string.Empty; + } + // Note that Http.Sys currently collapses all headers of the same name to a single coma separated string, + // so we can just call Set. + unknownHeaders[headerName] = headerValue; + } + pUnknownHeader++; + } + } + } + } + + internal SocketAddress GetRemoteEndPoint() + { + return GetEndPoint(localEndpoint: false); + } + + internal SocketAddress GetLocalEndPoint() + { + return GetEndPoint(localEndpoint: true); + } + + private SocketAddress GetEndPoint(bool localEndpoint) + { + fixed (byte* pMemoryBlob = _backingBuffer) + { + var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); + var source = localEndpoint ? (byte*)request->Address.pLocalAddress : (byte*)request->Address.pRemoteAddress; + + if (source == null) + { + return null; + } + var address = (IntPtr)(pMemoryBlob + _bufferAlignment - (byte*)_originalBufferAddress + source); + return CopyOutAddress(address); + } + } + + private static SocketAddress CopyOutAddress(IntPtr address) + { + ushort addressFamily = *((ushort*)address); + if (addressFamily == (ushort)AddressFamily.InterNetwork) + { + var v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize); + fixed (byte* pBuffer = v4address.Buffer) + { + for (int index = 2; index < SocketAddress.IPv4AddressSize; index++) + { + pBuffer[index] = ((byte*)address)[index]; + } + } + return v4address; + } + if (addressFamily == (ushort)AddressFamily.InterNetworkV6) + { + var v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize); + fixed (byte* pBuffer = v6address.Buffer) + { + for (int index = 2; index < SocketAddress.IPv6AddressSize; index++) + { + pBuffer[index] = ((byte*)address)[index]; + } + } + return v6address; + } + + return null; + } + + internal uint GetChunks(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) + { + // Return value. + uint dataRead = 0; + fixed (byte* pMemoryBlob = _backingBuffer) + { + var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); + long fixup = pMemoryBlob - (byte*)_originalBufferAddress; + + if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) + { + var pDataChunk = (HttpApi.HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); + + fixed (byte* pReadBuffer = buffer) + { + byte* pTo = &pReadBuffer[offset]; + + while (dataChunkIndex < request->EntityChunkCount && dataRead < size) + { + if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength) + { + dataChunkOffset = 0; + dataChunkIndex++; + pDataChunk++; + } + else + { + byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup; + + uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset; + if (bytesToRead > (uint)size) + { + bytesToRead = (uint)size; + } + for (uint i = 0; i < bytesToRead; i++) + { + *(pTo++) = *(pFrom++); + } + dataRead += bytesToRead; + dataChunkOffset += bytesToRead; + } + } + } + } + // we're finished. + if (dataChunkIndex == request->EntityChunkCount) + { + dataChunkIndex = -1; + } + } + + return dataRead; } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 924b7eef2c..d7fce4acb0 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -25,7 +25,6 @@ using System; using System.Globalization; using System.IO; using System.Net; -using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -51,46 +50,27 @@ namespace Microsoft.Net.Http.Server private bool _isDisposed = false; - internal unsafe Request(RequestContext requestContext, NativeRequestContext memoryBlob) + internal Request(RequestContext requestContext, NativeRequestContext nativeRequestContext) { // TODO: Verbose log RequestContext = requestContext; - _nativeRequestContext = memoryBlob; + _nativeRequestContext = nativeRequestContext; _contentBoundaryType = BoundaryType.None; - // Set up some of these now to avoid refcounting on memory blob later. - RequestId = memoryBlob.RequestBlob->RequestId; - UConnectionId = memoryBlob.RequestBlob->ConnectionId; - SslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure : - memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : - SslStatus.ClientCert; + RequestId = nativeRequestContext.RequestId; + UConnectionId = nativeRequestContext.ConnectionId; + SslStatus = nativeRequestContext.SslStatus; - KnownMethod = memoryBlob.RequestBlob->Verb; - Method = HttpApi.GetVerb(memoryBlob.RequestBlob); + KnownMethod = nativeRequestContext.VerbId; + Method = _nativeRequestContext.GetVerb(); - if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0) - { - RawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); - } + RawUrl = nativeRequestContext.GetRawUrl(); - HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl; - if (cookedUrl.pHost != null && cookedUrl.HostLength > 0) - { - // TODO: Unused - // _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2); - } - var cookedUrlPath = string.Empty; - if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0) - { - cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); - } - QueryString = string.Empty; - if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0) - { - QueryString = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); - } + var cookedUrl = nativeRequestContext.GetCookedUrl(); + var cookedUrlPath = cookedUrl.GetAbsPath() ?? string.Empty; + QueryString = cookedUrl.GetQueryString() ?? string.Empty; - var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)memoryBlob.RequestBlob->UrlContext); + var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)nativeRequestContext.UrlContext); var originalPath = RequestUriBuilder.GetRequestPath(RawUrl, cookedUrlPath, RequestContext.Logger); // 'OPTIONS * HTTP/1.1' @@ -114,25 +94,11 @@ namespace Microsoft.Net.Http.Server Path = originalPath.Substring(prefix.Path.Length - 1); } - int major = memoryBlob.RequestBlob->Version.MajorVersion; - int minor = memoryBlob.RequestBlob->Version.MinorVersion; - if (major == 1 && minor == 1) - { - ProtocolVersion = Constants.V1_1; - } - else if (major == 1 && minor == 0) - { - ProtocolVersion = Constants.V1_0; - } - else - { - ProtocolVersion = new Version(major, minor); - } + ProtocolVersion = _nativeRequestContext.GetVersion(); Headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); - var requestV2 = (HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob; - User = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount); + User = nativeRequestContext.GetUser(); // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/WebListener/issues/231 @@ -141,33 +107,6 @@ namespace Microsoft.Net.Http.Server // TODO: Verbose log parameters } - internal byte[] RequestBuffer - { - get - { - CheckDisposed(); - return _nativeRequestContext.RequestBuffer; - } - } - - internal int BufferAlignment - { - get - { - CheckDisposed(); - return _nativeRequestContext.BufferAlignment; - } - } - - internal IntPtr OriginalBlobAddress - { - get - { - CheckDisposed(); - return _nativeRequestContext.OriginalBlobAddress; - } - } - internal ulong UConnectionId { get; } // No ulongs in public APIs... @@ -260,7 +199,7 @@ namespace Microsoft.Net.Http.Server { if (_remoteEndPoint == null) { - _remoteEndPoint = HttpApi.GetRemoteEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress); + _remoteEndPoint = _nativeRequestContext.GetRemoteEndPoint(); } return _remoteEndPoint; @@ -273,7 +212,7 @@ namespace Microsoft.Net.Http.Server { if (_localEndPoint == null) { - _localEndPoint = HttpApi.GetLocalEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress); + _localEndPoint = _nativeRequestContext.GetLocalEndPoint(); } return _localEndPoint; @@ -356,6 +295,7 @@ namespace Microsoft.Net.Http.Server // Key: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_ENABLE_TOKEN_BINDING // Value: "iexplore.exe"=dword:00000001 // TODO: https://github.com/aspnet/WebListener/issues/231 + // TODO: https://github.com/aspnet/WebListener/issues/204 Move to NativeRequestContext /* private unsafe void GetTlsTokenBindingInfo() { @@ -371,6 +311,11 @@ namespace Microsoft.Net.Http.Server } } */ + internal uint GetChunks(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) + { + return _nativeRequestContext.GetChunks(ref dataChunkIndex, ref dataChunkOffset, buffer, offset, size); + } + // should only be called from RequestContext internal void Dispose() { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs index a1c526d68b..2b3f1dcafb 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs @@ -85,14 +85,12 @@ namespace Microsoft.Net.Http.Server private string GetKnownHeader(HttpSysRequestHeader header) { - return HttpApi.GetKnownHeader(_requestMemoryBlob.RequestBuffer, - _requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress, (int)header); + return _requestMemoryBlob.GetKnownHeader(header); } private void GetUnknownHeaders(IDictionary extra) { - HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer, - _requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress); + _requestMemoryBlob.GetUnknownHeaders(extra); } void IDictionary.Add(string key, StringValues value) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 16324aa487..9ad00ca84d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -154,9 +154,7 @@ namespace Microsoft.Net.Http.Server if (_dataChunkIndex != -1) { - dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer, - _requestContext.Request.BufferAlignment, _requestContext.Request.OriginalBlobAddress, - ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); } if (_dataChunkIndex == -1 && dataRead < size) @@ -232,8 +230,7 @@ namespace Microsoft.Net.Http.Server uint dataRead = 0; if (_dataChunkIndex != -1) { - dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, - _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); if (_dataChunkIndex != -1 && dataRead == size) { @@ -350,8 +347,7 @@ namespace Microsoft.Net.Http.Server uint dataRead = 0; if (_dataChunkIndex != -1) { - dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment, - _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); + dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); if (_dataChunkIndex != -1 && dataRead == size) { UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead); diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index cb72439299..2e2f0cb1f8 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -319,9 +319,9 @@ namespace Microsoft.Net.Http.Server internal unsafe bool ValidateRequest(NativeRequestContext requestMemory) { // Block potential DOS attacks - if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit) + if (requestMemory.UnknownHeaderCount > UnknownHeaderLimit) { - SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest, authChallenges: null); + SendError(requestMemory.RequestId, HttpStatusCode.BadRequest, authChallenges: null); return false; } return true; @@ -329,10 +329,9 @@ namespace Microsoft.Net.Http.Server internal unsafe bool ValidateAuth(NativeRequestContext requestMemory) { - var requestV2 = (HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob; - if (!Settings.Authentication.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo)) + if (!Settings.Authentication.AllowAnonymous && !requestMemory.CheckAuthenticated()) { - SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, + SendError(requestMemory.RequestId, HttpStatusCode.Unauthorized, AuthenticationManager.GenerateChallenges(Settings.Authentication.Schemes)); return false; } diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index ff48f77414..0075622980 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Theory] + [Theory(Skip = "https://github.com/aspnet/WebListener/issues/210")] [InlineData("Set-cookie")] [InlineData("vary")] [InlineData("pragma")] @@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] public async Task Caching_ExpiresWithoutPublic_NotCached() { var requestCount = 1; From 735366ff3f05c0f9aef1162fb06b700e5fd6f9e7 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 1 Sep 2016 09:45:46 -0700 Subject: [PATCH 387/597] Revert buffer alignment in NativeRequestContext The buffer alignment will be set to zero so that WebListener will work properly in all environment except ARM --- .../RequestProcessing/NativeRequestContext.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 32a93e8ae6..193d419d29 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -132,10 +132,18 @@ namespace Microsoft.Net.Http.Server _nativeOverlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, _backingBuffer)); - // HttpReceiveHttpRequest expects the request pointer to be 8-byte-aligned or it fails. On ARM - // CLR creates buffers that are 4-byte-aligned so we need force 8-byte alignment. var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); - _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07); + + // TODO: + // Apparently the HttpReceiveHttpRequest memory alignment requirements for non - ARM processors + // are different than for ARM processors. We have seen 4 - byte - aligned buffers allocated on + // virtual x64/x86 machines which were accepted by HttpReceiveHttpRequest without errors. In + // these cases the buffer alignment may cause reading values at invalid offset. Setting buffer + // alignment to 0 for now. + // + // _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07); + + _bufferAlignment = 0; _nativeRequest = (HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment); } From f05007e0f28e97ad4166b8b27c6af313127f9d67 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 1 Sep 2016 12:00:06 -0700 Subject: [PATCH 388/597] Fix error message in RequestContext --- .../RequestProcessing/RequestContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 00044c2eed..0f533cd730 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -247,7 +247,7 @@ namespace Microsoft.Net.Http.Server { if (!IsUpgradableRequest) { - throw new InvalidOperationException("This request is cannot be upgraded."); + throw new InvalidOperationException("This request cannot be upgraded."); } WebSocketHelpers.ValidateOptions(subProtocol, keepAliveInterval); From 6522926c2232123794ad7a343e3a25db5cfcfadd Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 2 Sep 2016 15:33:10 -0700 Subject: [PATCH 389/597] Port WebSocket fix from https://github.com/dotnet/corefx/pull/11348 --- .../System/Net/WebSockets/ManagedWebSocket.cs | 16 +++++----------- src/Microsoft.Net.Http.Server/project.json | 4 +--- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs index 738b0a7348..8253aebde5 100644 --- a/src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs +++ b/src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs @@ -30,7 +30,6 @@ namespace System.Net.WebSockets /// The connected Stream. /// true if this is the server-side of the connection; false if this is the client-side of the connection. /// The agreed upon subprotocol for the connection. - /// The current state of the websocket connection. /// The interval to use for keep-alive pings. /// The buffer size to use for received data. /// The created instance. @@ -616,12 +615,7 @@ namespace System.Net.WebSockets // Make sure we have the first two bytes, which includes the start of the payload length. if (_receiveBufferCount < 2) { - await EnsureBufferContainsAsync(2, cancellationToken, throwOnPrematureClosure: false).ConfigureAwait(false); - if (_receiveBufferCount < 2) - { - // The connection closed; nothing more to read. - return new WebSocketReceiveResult(0, WebSocketMessageType.Text, true); - } + await EnsureBufferContainsAsync(2, cancellationToken, throwOnPrematureClosure: true).ConfigureAwait(false); } // Then make sure we have the full header based on the payload length. @@ -877,7 +871,7 @@ namespace System.Net.WebSockets } /// Parses a message header from the buffer. This assumes the header is in the buffer. - /// The read header. + /// The read header. /// true if a header was read; false if the header was invalid. private bool TryParseMessageHeaderFromReceiveBuffer(out MessageHeader resultHeader) { @@ -1035,7 +1029,7 @@ namespace System.Net.WebSockets /// Sends a close message to the server. /// The close status to send. - /// The close status description to send. + /// The close status description to send. /// The CancellationToken to use to cancel the websocket. private async Task SendCloseFrameAsync(WebSocketCloseStatus closeStatus, string closeStatusDescription, CancellationToken cancellationToken) { @@ -1151,9 +1145,9 @@ namespace System.Net.WebSockets /// The buffer to which the mask should be applied. /// The offset into at which the mask should start to be applied. /// The four-byte mask, stored as an Int32. - /// The index into the mas + /// The index into the mask. /// The number of bytes to mask. - /// + /// The next index into the mask to be used for future applications of the mask. private static unsafe int ApplyMask(byte[] toMask, int toMaskOffset, int mask, int maskIndex, long count) { Debug.Assert(toMaskOffset <= toMask.Length - count, $"Unexpected inputs: {toMaskOffset}, {toMask.Length}, {count}"); diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index e23549b60d..c7083374f7 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -10,9 +10,7 @@ "warningsAsErrors": true, "keyFile": "../../tools/Key.snk", "nowarn": [ - "CS1591", - "CS1572", - "CS1573" + "CS1591" ], "xmlDoc": true }, From 88114568b9f1c9708c0e1fecd11d90978fa600c4 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 31 Aug 2016 14:09:17 -0700 Subject: [PATCH 390/597] #167 Prevent duplicate Content-Length headers --- .../RequestProcessing/Response.cs | 22 ++++++++----------- .../RequestProcessing/ResponseStream.cs | 10 ++++----- .../ResponseCachingTests.cs | 3 +-- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 07622b5a87..534529e198 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -338,11 +338,6 @@ namespace Microsoft.Net.Http.Server _responseState = ResponseState.Started; var reasonPhrase = GetReasonPhrase(StatusCode); - /* - if (m_BoundaryType==BoundaryType.Raw) { - use HTTP_SEND_RESPONSE_FLAG_RAW_HEADER; - } - */ uint statusCode; uint bytesSent; List pinnedHeaders = SerializeHeaders(isOpaqueUpgrade); @@ -414,7 +409,7 @@ namespace Microsoft.Net.Http.Server return statusCode; } - internal HttpApi.HTTP_FLAGS ComputeHeaders(bool endOfRequest = false) + internal HttpApi.HTTP_FLAGS ComputeHeaders(long writeCount, bool endOfRequest = false) { // 401 if (StatusCode == (ushort)HttpStatusCode.Unauthorized) @@ -456,6 +451,13 @@ namespace Microsoft.Net.Http.Server _boundaryType = BoundaryType.ContentLength; // ComputeLeftToWrite checks for HEAD requests when setting _leftToWrite _expectedBodyLength = responseContentLength.Value; + if (responseContentLength.Value == writeCount && !isHeadRequest) + { + // A single write with the whole content-length. Http.Sys will set the content-length for us in this scenario. + // If we don't remove it then range requests served from cache will have two. + // https://github.com/aspnet/WebListener/issues/167 + ContentLength = null; + } } else if (responseChunkedSet) { @@ -495,7 +497,6 @@ namespace Microsoft.Net.Http.Server flags = HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } - Headers.IsReadOnly = true; // Prohibit further modifications. return flags; } @@ -511,12 +512,7 @@ namespace Microsoft.Net.Http.Server HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; List pinnedHeaders; GCHandle gcHandle; - /* - // here we would check for BoundaryType.Raw, in this case we wouldn't need to do anything - if (m_BoundaryType==BoundaryType.Raw) { - return null; - } - */ + if (Headers.Count == 0) { return null; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 4d23aafa68..ddb009ee6f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -137,7 +137,7 @@ namespace Microsoft.Net.Http.Server } // Make sure all validation is performed before this computes the headers - var flags = ComputeLeftToWrite(endOfRequest); + var flags = ComputeLeftToWrite(data.Count, endOfRequest); if (!_inOpaqueMode && endOfRequest && _leftToWrite > 0) { _requestContext.Abort(); @@ -315,7 +315,7 @@ namespace Microsoft.Net.Http.Server } // Make sure all validation is performed before this computes the headers - var flags = ComputeLeftToWrite(); + var flags = ComputeLeftToWrite(data.Count); if (_leftToWrite != data.Count) { flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; @@ -438,12 +438,12 @@ namespace Microsoft.Net.Http.Server _requestContext.Abort(); } - private HttpApi.HTTP_FLAGS ComputeLeftToWrite(bool endOfRequest = false) + private HttpApi.HTTP_FLAGS ComputeLeftToWrite(long writeCount, bool endOfRequest = false) { var flags = HttpApi.HTTP_FLAGS.NONE; if (!_requestContext.Response.HasComputedHeaders) { - flags = _requestContext.Response.ComputeHeaders(endOfRequest); + flags = _requestContext.Response.ComputeHeaders(writeCount, endOfRequest); } if (_leftToWrite == long.MinValue) { @@ -591,7 +591,7 @@ namespace Microsoft.Net.Http.Server } // Make sure all validation is performed before this computes the headers - var flags = ComputeLeftToWrite(); + var flags = ComputeLeftToWrite(count.Value); uint statusCode; uint bytesSent = 0; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 349f93ecfe..63bf4e3537 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -1000,8 +1000,7 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "Cached response contains duplicate Content-Length headers (#167).")] + [Fact] public async Task Caching_RequestRangeFromCachedFile_ServedFromCache() { string address; From 8105a272d2e79ca70119fadd01dd3b1c4160aa79 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 1 Sep 2016 10:17:42 -0700 Subject: [PATCH 391/597] #210 Re-enable caching tests --- .../ResponseCachingTests.cs | 26 ++++-- .../ResponseCachingTests.cs | 81 +++++++++++++------ 2 files changed, 73 insertions(+), 34 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index 0075622980..6c63806476 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests { httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -27,7 +28,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_JustPublic_NotCached() { var requestCount = 1; @@ -37,6 +38,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -45,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_MaxAge_Cached() { var requestCount = 1; @@ -55,6 +57,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -63,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SMaxAge_Cached() { var requestCount = 1; @@ -73,6 +76,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, s-maxage=10"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -81,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SMaxAgeAndMaxAge_SMaxAgePreferredCached() { var requestCount = 1; @@ -91,6 +95,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=0, s-maxage=10"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -99,7 +104,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_Expires_Cached() { var requestCount = 1; @@ -110,6 +115,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; httpContext.Response.Headers["Expires"] = (DateTime.UtcNow + TimeSpan.FromSeconds(10)).ToString("r"); + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -118,7 +124,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Theory(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Theory] [InlineData("Set-cookie")] [InlineData("vary")] [InlineData("pragma")] @@ -132,6 +138,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; httpContext.Response.Headers[headerName] = "headerValue"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -153,6 +160,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; httpContext.Response.Headers["Expires"] = expiresValue; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -161,7 +169,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_ExpiresWithoutPublic_NotCached() { var requestCount = 1; @@ -171,6 +179,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Expires"] = (DateTime.UtcNow + TimeSpan.FromSeconds(10)).ToString("r"); + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -179,7 +188,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_MaxAgeAndExpires_MaxAgePreferred() { var requestCount = 1; @@ -190,6 +199,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; httpContext.Response.Headers["Expires"] = (DateTime.UtcNow - TimeSpan.FromSeconds(10)).ToString("r"); // In the past + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 63bf4e3537..5a062f878d 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -56,7 +56,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetTtlWithContentType_Cached() { string address; @@ -83,7 +83,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] // Http.Sys does not set the optional Age header for cached content. // http://tools.ietf.org/html/rfc7234#section-5.1 public async Task Caching_CheckAge_NotSentWithCachedContent() @@ -114,7 +114,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] // Http.Sys does not update the optional Age header for cached content. // http://tools.ietf.org/html/rfc7234#section-5.1 public async Task Caching_SetAge_AgeHeaderCachedAndNotUpdated() @@ -250,7 +250,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetTtlHuge_Cached() { string address; @@ -277,7 +277,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetTtlAndWriteBody_Cached() { string address; @@ -288,21 +288,50 @@ namespace Microsoft.Net.Http.Server var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = 10; context.Response.CacheTtl = TimeSpan.FromSeconds(10); context.Response.Body.Write(new byte[10], 0, 10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_SetTtlAndWriteAsyncBody_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = 10; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); - Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); // Send a second request and make sure we get the same response (without listening for one on the server). response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); - Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); } } @@ -373,7 +402,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_WriteFullContentLength_Cached() { string address; @@ -435,7 +464,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SendFileWithFullContentLength_Cached() { string address; @@ -464,19 +493,20 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetTtlAndStatusCode_Cached() { string address; using (var server = Utilities.CreateHttpServer(out address)) { - // Http.Sys will cache any status code. + // Http.Sys will cache almost any status code. for (int status = 200; status < 600; status++) { - // 407 (Proxy Authentication Required) makes CoreCLR's HttpClient throw - if (status == 407) + switch (status) { - continue; + case 206: // 206 (Partial Content) is not cached + case 407: // 407 (Proxy Authentication Required) makes CoreCLR's HttpClient throw + continue; } var responseTask = SendRequestAsync(address + status); @@ -561,7 +591,7 @@ namespace Microsoft.Net.Http.Server // RFC violation. http://tools.ietf.org/html/rfc7234#section-4.4 // "A cache MUST invalidate the effective Request URI ... when a non-error status code // is received in response to an unsafe request method." - [Theory(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Theory] // See HTTP_VERB for known verbs [InlineData("HEAD")] [InlineData("UNKNOWN")] @@ -628,7 +658,7 @@ namespace Microsoft.Net.Http.Server // RFC violation / implementation limiation, Vary is not respected. // http://tools.ietf.org/html/rfc7234#section-4.1 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetVary_NotRespected() { string address; @@ -729,7 +759,7 @@ namespace Microsoft.Net.Http.Server // Responses can be cached for requests with Pragma: no-cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestPragmaNoCache_Cached() { string address; @@ -758,7 +788,7 @@ namespace Microsoft.Net.Http.Server // RFC violation, Requests with Pragma: no-cache should not be served from cache. // http://tools.ietf.org/html/rfc7234#section-5.4 // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestPragmaNoCache_NotRespectedAndServedFromCache() { string address; @@ -786,7 +816,7 @@ namespace Microsoft.Net.Http.Server // Responses can be cached for requests with cache-control: no-cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestCacheControlNoCache_Cached() { string address; @@ -814,7 +844,7 @@ namespace Microsoft.Net.Http.Server // RFC violation, Requests with Cache-Control: no-cache should not be served from cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestCacheControlNoCache_NotRespectedAndServedFromCache() { string address; @@ -842,7 +872,7 @@ namespace Microsoft.Net.Http.Server // RFC violation // http://tools.ietf.org/html/rfc7234#section-5.2.1.1 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestCacheControlMaxAgeZero_NotRespectedAndServedFromCache() { string address; @@ -870,7 +900,7 @@ namespace Microsoft.Net.Http.Server // RFC violation // http://tools.ietf.org/html/rfc7234#section-5.2.1.3 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestCacheControlMinFreshOutOfRange_NotRespectedAndServedFromCache() { string address; @@ -941,8 +971,7 @@ namespace Microsoft.Net.Http.Server } // http://tools.ietf.org/html/rfc7233#section-4.1 - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "Cached response contains duplicate Content-Length headers (#167).")] + [Fact] public async Task Caching_RequestRangeFromCache_RangeServedFromCache() { string address; @@ -972,7 +1001,7 @@ namespace Microsoft.Net.Http.Server } // http://tools.ietf.org/html/rfc7233#section-4.1 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestMultipleRangesFromCache_RangesServedFromCache() { string address; @@ -1032,7 +1061,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestMultipleRangesFromCachedFile_ServedFromCache() { string address; From 1e59352466d14f7ecc0a9a028ca9359d13a84c6f Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 1 Sep 2016 12:00:05 -0700 Subject: [PATCH 392/597] Consolidate write flags and counting logic --- .../RequestProcessing/ResponseStream.cs | 76 ++++++------------- 1 file changed, 25 insertions(+), 51 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index ddb009ee6f..4db16705ed 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -40,7 +40,6 @@ namespace Microsoft.Net.Http.Server private long _leftToWrite = long.MinValue; private bool _skipWrites; private bool _disposed; - private bool _inOpaqueMode; // The last write needs special handling to cancel. private ResponseStreamAsyncResult _lastWrite; @@ -138,7 +137,7 @@ namespace Microsoft.Net.Http.Server // Make sure all validation is performed before this computes the headers var flags = ComputeLeftToWrite(data.Count, endOfRequest); - if (!_inOpaqueMode && endOfRequest && _leftToWrite > 0) + if (endOfRequest && _leftToWrite > 0) { _requestContext.Abort(); // This is logged rather than thrown because it is too late for an exception to be visible in user code. @@ -146,16 +145,6 @@ namespace Microsoft.Net.Http.Server return; } - if (endOfRequest && _requestContext.Response.BoundaryType == BoundaryType.Close) - { - flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; - } - else if (!endOfRequest && _leftToWrite != data.Count) - { - flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - } - - UpdateWritenCount((uint)data.Count); uint statusCode = 0; HttpApi.HTTP_DATA_CHUNK[] dataChunks; var pinnedBuffers = PinDataBuffers(endOfRequest, data, out dataChunks); @@ -316,12 +305,6 @@ namespace Microsoft.Net.Http.Server // Make sure all validation is performed before this computes the headers var flags = ComputeLeftToWrite(data.Count); - if (_leftToWrite != data.Count) - { - flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - } - - UpdateWritenCount((uint)data.Count); uint statusCode = 0; var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; var asyncResult = new ResponseStreamAsyncResult(this, data, chunked, cancellationToken); @@ -460,6 +443,29 @@ namespace Microsoft.Net.Http.Server _leftToWrite = -1; // unlimited } } + + if (endOfRequest && _requestContext.Response.BoundaryType == BoundaryType.Close) + { + flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; + } + else if (!endOfRequest && _leftToWrite != writeCount) + { + flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + } + + // Update _leftToWrite now so we can queue up additional async writes. + if (_leftToWrite > 0) + { + // keep track of the data transferred + _leftToWrite -= writeCount; + } + if (_leftToWrite == 0) + { + // in this case we already passed 0 as the flag, so we don't need to call HttpSendResponseEntityBody() when we Close() + _disposed = true; + } + // else -1 unlimited + return flags; } @@ -597,20 +603,6 @@ namespace Microsoft.Net.Http.Server var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; var asyncResult = new ResponseStreamAsyncResult(this, fileStream, offset, count.Value, chunked, cancellationToken); - long bytesWritten; - if (chunked) - { - bytesWritten = 0; - } - else - { - bytesWritten = count.Value; - } - - // Update _leftToWrite now so we can queue up additional calls to SendFileAsync. - flags |= _leftToWrite == bytesWritten ? HttpApi.HTTP_FLAGS.NONE : HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - UpdateWritenCount((uint)bytesWritten); - try { if (!started) @@ -680,23 +672,6 @@ namespace Microsoft.Net.Http.Server return asyncResult.Task; } - private void UpdateWritenCount(uint dataWritten) - { - if (!_inOpaqueMode) - { - if (_leftToWrite > 0) - { - // keep track of the data transferred - _leftToWrite -= dataWritten; - } - if (_leftToWrite == 0) - { - // in this case we already passed 0 as the flag, so we don't need to call HttpSendResponseEntityBody() when we Close() - _disposed = true; - } - } - } - protected override unsafe void Dispose(bool disposing) { try @@ -719,8 +694,7 @@ namespace Microsoft.Net.Http.Server internal void SwitchToOpaqueMode() { - _inOpaqueMode = true; - _leftToWrite = long.MaxValue; + _leftToWrite = -1; } // The final Content-Length async write can only be Canceled by CancelIoEx. From e9ef38cf3a457623e845867d05e171ee5df42105 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 2 Sep 2016 16:23:30 -0700 Subject: [PATCH 393/597] PR feedback --- .../RequestProcessing/Response.cs | 2 +- .../ResponseCachingTests.cs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 534529e198..628d910c5e 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -451,7 +451,7 @@ namespace Microsoft.Net.Http.Server _boundaryType = BoundaryType.ContentLength; // ComputeLeftToWrite checks for HEAD requests when setting _leftToWrite _expectedBodyLength = responseContentLength.Value; - if (responseContentLength.Value == writeCount && !isHeadRequest) + if (_expectedBodyLength == writeCount && !isHeadRequest) { // A single write with the whole content-length. Http.Sys will set the content-length for us in this scenario. // If we don't remove it then range requests served from cache will have two. diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 5a062f878d..b3a3b1da74 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -291,6 +291,8 @@ namespace Microsoft.Net.Http.Server context.Response.ContentLength = 10; context.Response.CacheTtl = TimeSpan.FromSeconds(10); context.Response.Body.Write(new byte[10], 0, 10); + // Http.Sys will add this for us + Assert.Null(context.Response.ContentLength); context.Dispose(); var response = await responseTask; @@ -320,6 +322,8 @@ namespace Microsoft.Net.Http.Server context.Response.ContentLength = 10; context.Response.CacheTtl = TimeSpan.FromSeconds(10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); + // Http.Sys will add this for us + Assert.Null(context.Response.ContentLength); context.Dispose(); var response = await responseTask; @@ -416,6 +420,8 @@ namespace Microsoft.Net.Http.Server context.Response.ContentLength = 10; context.Response.CacheTtl = TimeSpan.FromSeconds(10); context.Response.Body.Write(new byte[10], 0, 10); + // Http.Sys will add this for us + Assert.Null(context.Response.ContentLength); context.Dispose(); var response = await responseTask; @@ -478,6 +484,8 @@ namespace Microsoft.Net.Http.Server context.Response.ContentLength =_fileLength; context.Response.CacheTtl = TimeSpan.FromSeconds(10); await context.Response.SendFileAsync(_absoluteFilePath, 0, null, CancellationToken.None); + // Http.Sys will add this for us + Assert.Null(context.Response.ContentLength); context.Dispose(); var response = await responseTask; From 8aaa4d0759d17ca8898198f2f28ddc95caf5fb49 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Wed, 31 Aug 2016 12:11:56 -0700 Subject: [PATCH 394/597] Add test cases for Path unescaping --- .../RequestTests.cs | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index ce7db01208..0807e0cc5e 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -252,6 +252,130 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + [Theory] + [InlineData("%D0%A4", "Ф")] + [InlineData("%d0%a4", "Ф")] + [InlineData("%E0%A4%AD", "भ")] + [InlineData("%e0%A4%Ad", "भ")] + [InlineData("%F0%A4%AD%A2", "𤭢")] + [InlineData("%F0%a4%Ad%a2", "𤭢")] + [InlineData("%48%65%6C%6C%6F%20%57%6F%72%6C%64", "Hello World")] + [InlineData("%48%65%6C%6C%6F%2D%C2%B5%40%C3%9F%C3%B6%C3%A4%C3%BC%C3%A0%C3%A1", "Hello-µ@ßöäüàá")] + // Test the borderline cases of overlong UTF8. + [InlineData("%C2%80", "\u0080")] + [InlineData("%E0%A0%80", "\u0800")] + [InlineData("%F0%90%80%80", "\U00010000")] + [InlineData("%63", "c")] + [InlineData("%32", "2")] + [InlineData("%20", " ")] + // Mixed + [InlineData("%%32", "%2")] + [InlineData("%%20", "% ")] + public async Task Request_PathDecodingValidUTF8(string requestPath, string expect) + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => + { + Assert.Equal(expect, httpContext.Request.Path.Value.TrimStart('/')); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(root + "/" + requestPath); + Assert.Equal(string.Empty, response); + } + } + + [Theory] + [InlineData("%C3%84ra%20Benetton", "Ära Benetton")] + [InlineData("%E6%88%91%E8%87%AA%E6%A8%AA%E5%88%80%E5%90%91%E5%A4%A9%E7%AC%91%E5%8E%BB%E7%95%99%E8%82%9D%E8%83%86%E4%B8%A4%E6%98%86%E4%BB%91", "我自横刀向天笑去留肝胆两昆仑")] + public async Task Request_PathDecodingInternationalized(string requestPath, string expect) + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => + { + Assert.Equal(expect, httpContext.Request.Path.Value.TrimStart('/')); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(root + "/" + requestPath); + Assert.Equal(string.Empty, response); + } + } + + [Theory] + // Incomplete + [InlineData("%", "%")] + [InlineData("%%", "%%")] + [InlineData("%A", "%A")] + [InlineData("%Y", "%Y")] + public async Task Request_PathDecodingInvalidUTF8(string requestPath, string expect) + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => + { + var actualPath = httpContext.Request.Path.Value.TrimStart('/'); + Assert.Equal(expect, actualPath); + + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(root + "/" + requestPath); + Assert.Equal(string.Empty, response); + } + } + + // This test case ensures the consistency of current server behavior through it is not + // an idea one. + [Theory] + // Overlong ASCII + [InlineData("%C0%A4", true, HttpStatusCode.OK)] + [InlineData("%C1%BF", true, HttpStatusCode.OK)] + [InlineData("%E0%80%AF", true, HttpStatusCode.OK)] + [InlineData("%E0%9F%BF", true, HttpStatusCode.OK)] + [InlineData("%F0%80%80%AF", true, HttpStatusCode.OK)] + [InlineData("%F0%8F%8F%BF", false, HttpStatusCode.BadRequest)] + // Mixed + [InlineData("%C0%A4%32", true, HttpStatusCode.OK)] + [InlineData("%32%C0%A4%32", true, HttpStatusCode.OK)] + [InlineData("%C0%32%A4", true, HttpStatusCode.OK)] + public async Task Request_ServerErrorFromInvalidUTF8(string requestPath, bool unescaped, HttpStatusCode expectStatus) + { + bool pathIsUnescaped = false; + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => + { + var actualPath = httpContext.Request.Path.Value.TrimStart('/'); + pathIsUnescaped = !string.Equals(actualPath, requestPath, StringComparison.Ordinal); + return Task.FromResult(0); + })) + { + using (var client = new HttpClient()) + { + var response = await client.GetAsync(root + "/" + requestPath); + Assert.Equal(expectStatus, response.StatusCode); + Assert.Equal(unescaped, pathIsUnescaped); + } + } + } + + [Theory] + [InlineData("%2F", "%2F")] + [InlineData("foo%2Fbar", "foo%2Fbar")] + [InlineData("foo%2F%20bar", "foo%2F bar")] + public async Task Request_PathDecodingSkipForwardSlash(string requestPath, string expect) + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => + { + Assert.Equal(expect, httpContext.Request.Path.Value.TrimStart('/')); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(root + "/" + requestPath); + Assert.Equal(string.Empty, response); + } + } + [Fact] public async Task Request_DoubleEscapingAllowed() { From ff97efe0d2bf75205e131b7a91d6a3f0e76ee558 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Sat, 3 Sep 2016 01:07:52 -0700 Subject: [PATCH 395/597] Overhaul the URL path unescaping --- .../RequestProcessing/NativeRequestContext.cs | 14 + .../RequestProcessing/Request.cs | 5 +- .../RequestProcessing/RequestUriBuilder.cs | 274 +-------------- .../RequestProcessing/UrlInByte.cs | 123 +++++++ .../RequestProcessing/UrlPathDecoder.cs | 313 ++++++++++++++++++ .../RequestTests.cs | 29 +- 6 files changed, 476 insertions(+), 282 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/UrlInByte.cs create mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/UrlPathDecoder.cs diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 193d419d29..c950358e0c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -181,6 +181,20 @@ namespace Microsoft.Net.Http.Server return null; } + internal byte[] GetRawUrlInBytes() + { + + if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0) + { + var result = new byte[NativeRequest->RawUrlLength]; + Marshal.Copy((IntPtr)NativeRequest->pRawUrl, result, 0, NativeRequest->RawUrlLength); + + return result; + } + + return null; + } + internal CookedUrl GetCookedUrl() { return new CookedUrl(NativeRequest->CookedUrl); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index d7fce4acb0..3063d777fc 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -67,11 +67,12 @@ namespace Microsoft.Net.Http.Server RawUrl = nativeRequestContext.GetRawUrl(); var cookedUrl = nativeRequestContext.GetCookedUrl(); - var cookedUrlPath = cookedUrl.GetAbsPath() ?? string.Empty; QueryString = cookedUrl.GetQueryString() ?? string.Empty; var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)nativeRequestContext.UrlContext); - var originalPath = RequestUriBuilder.GetRequestPath(RawUrl, cookedUrlPath, RequestContext.Logger); + + var rawUrlInBytes = _nativeRequestContext.GetRawUrlInBytes(); + var originalPath = RequestUriBuilder.GetRequestPath(rawUrlInBytes, RequestContext.Logger); // 'OPTIONS * HTTP/1.1' if (KnownMethod == HttpApi.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal)) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 26169bfa36..72f76068d1 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -21,296 +21,42 @@ // // ----------------------------------------------------------------------- -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; using System.Text; using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { // We don't use the cooked URL because http.sys unescapes all percent-encoded values. However, - // we also can't just use the raw Uri, since http.sys supports not only Utf-8, but also ANSI/DBCS and - // Unicode code points. System.Uri only supports Utf-8. + // we also can't just use the raw Uri, since http.sys supports not only UTF-8, but also ANSI/DBCS and + // Unicode code points. System.Uri only supports UTF-8. // The purpose of this class is to decode all UTF-8 percent encoded characters, with the // exception of %2F ('/'), which is left encoded. internal sealed class RequestUriBuilder { private static readonly Encoding Utf8Encoding; - private readonly string _rawUri; - private readonly string _cookedUriPath; - - // This field is used to build the final request Uri string from the Uri parts passed to the ctor. - private StringBuilder _requestUriString; - - // The raw path is parsed by looping through all characters from left to right. 'rawOctets' - // is used to store consecutive percent encoded octets as actual byte values: e.g. for path /pa%C3%84th%20/ - // rawOctets will be set to { 0xC3, 0x84 } when we reach character 't' and it will be { 0x20 } when - // we reach the final '/'. I.e. after a sequence of percent encoded octets ends, we use rawOctets as - // input to the encoding and decode them into a string. - private List _rawOctets; - private string _rawPath; - - private ILogger _logger; - static RequestUriBuilder() { Utf8Encoding = new UTF8Encoding(false, true); } - private RequestUriBuilder(string rawUri, string cookedUriPath, ILogger logger) - { - Debug.Assert(!string.IsNullOrEmpty(rawUri), "Empty raw URL."); - Debug.Assert(!string.IsNullOrEmpty(cookedUriPath), "Empty cooked URL path."); - Debug.Assert(logger != null, "Null logger."); - - this._rawUri = rawUri; - this._cookedUriPath = AddSlashToAsteriskOnlyPath(cookedUriPath); - this._logger = logger; - } - - private enum ParsingResult - { - Success, - InvalidString, - EncodingError - } - // Process only the path. - internal static string GetRequestPath(string rawUri, string cookedUriPath, ILogger logger) + public static string GetRequestPath(byte[] rawUriInBytes, ILogger logger) { - RequestUriBuilder builder = new RequestUriBuilder(rawUri, cookedUriPath, logger); + //Debug.Assert(rawUriInBytes == null || rawUriInBytes.Length == 0, "Empty raw URL."); + //Debug.Assert(logger != null, "Null logger."); - return builder.GetPath(); - } + var rawUriInByte = new UrlInByte(rawUriInBytes); + var pathInByte = rawUriInByte.Path; - private string GetPath() - { - // Initialize 'rawPath' only if really needed; i.e. if we build the request Uri from the raw Uri. - _rawPath = GetPath(_rawUri); - - // If HTTP.sys only parses Utf-8, we can safely use the raw path: it must be a valid Utf-8 string. - if (!HttpSysSettings.EnableNonUtf8 || string.IsNullOrEmpty(_rawPath)) - { - if (string.IsNullOrEmpty(_rawPath)) - { - _rawPath = "/"; - } - return _rawPath; - } - - _rawOctets = new List(); - _requestUriString = new StringBuilder(); - ParsingResult result = ParseRawPath(Utf8Encoding); - - if (result == ParsingResult.Success) - { - return _requestUriString.ToString(); - } - - // Fallback - return _cookedUriPath; - } - - private ParsingResult ParseRawPath(Encoding encoding) - { - Debug.Assert(encoding != null, "'encoding' must be assigned."); - - int index = 0; - char current = '\0'; - while (index < _rawPath.Length) - { - current = _rawPath[index]; - if (current == '%') - { - // Assert is enough, since http.sys accepted the request string already. This should never happen. - Debug.Assert(index + 2 < _rawPath.Length, "Expected at least 2 characters after '%' (e.g. %20)"); - - // We have a percent encoded octet: %XX - var octetString = _rawPath.Substring(index + 1, 2); - - // Leave %2F as is, otherwise add to raw octets list for unescaping - if (octetString == "2F" || octetString == "2f") - { - _requestUriString.Append('%'); - _requestUriString.Append(octetString); - } - else if (!AddPercentEncodedOctetToRawOctetsList(encoding, octetString)) - { - return ParsingResult.InvalidString; - } - - index += 3; - } - else - { - if (!EmptyDecodeAndAppendDecodedOctetsList(encoding)) - { - return ParsingResult.EncodingError; - } - - // Append the current character to the result. - _requestUriString.Append(current); - index++; - } - } - - // if the raw path ends with a sequence of percent encoded octets, make sure those get added to the - // result (requestUriString). - if (!EmptyDecodeAndAppendDecodedOctetsList(encoding)) - { - return ParsingResult.EncodingError; - } - - return ParsingResult.Success; - } - - private bool AddPercentEncodedOctetToRawOctetsList(Encoding encoding, string escapedCharacter) - { - byte encodedValue; - if (!byte.TryParse(escapedCharacter, NumberStyles.HexNumber, null, out encodedValue)) - { - LogHelper.LogDebug(_logger, nameof(AddPercentEncodedOctetToRawOctetsList), "Can't convert code point: " + escapedCharacter); - return false; - } - - _rawOctets.Add(encodedValue); - - return true; - } - - private bool EmptyDecodeAndAppendDecodedOctetsList(Encoding encoding) - { - if (_rawOctets.Count == 0) - { - return true; - } - - string decodedString = null; - try - { - // If the encoding can get a string out of the byte array, this is a valid string in the - // 'encoding' encoding. - var bytes = _rawOctets.ToArray(); - decodedString = encoding.GetString(bytes, 0, bytes.Length); - - _requestUriString.Append(decodedString); - _rawOctets.Clear(); - - return true; - } - catch (DecoderFallbackException e) - { - LogHelper.LogDebug(_logger, nameof(EmptyDecodeAndAppendDecodedOctetsList), "Can't convert bytes: " + GetOctetsAsString(_rawOctets) + ": " + e.Message); - } - - return false; - } - - private static string GetOctetsAsString(IEnumerable octets) - { - StringBuilder octetString = new StringBuilder(); - - bool first = true; - foreach (byte octet in octets) - { - if (first) - { - first = false; - } - else - { - octetString.Append(" "); - } - octetString.Append(octet.ToString("X2", CultureInfo.InvariantCulture)); - } - - return octetString.ToString(); - } - - private static string GetPath(string uriString) - { - Debug.Assert(uriString != null, "uriString must not be null"); - Debug.Assert(uriString.Length > 0, "uriString must not be empty"); - - int pathStartIndex = 0; - - // Perf. improvement: nearly all strings are relative Uris. So just look if the - // string starts with '/'. If so, we have a relative Uri and the path starts at position 0. - // (http.sys already trimmed leading whitespaces) - if (uriString[0] != '/') - { - // We can't check against cookedUriScheme, since http.sys allows for request http://myserver/ to - // use a request line 'GET https://myserver/' (note http vs. https). Therefore check if the - // Uri starts with either http:// or https://. - int authorityStartIndex = 0; - if (uriString.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) - { - authorityStartIndex = 7; - } - else if (uriString.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) - { - authorityStartIndex = 8; - } - - if (authorityStartIndex > 0) - { - // we have an absolute Uri. Find out where the authority ends and the path begins. - // Note that Uris like "http://server?query=value/1/2" are invalid according to RFC2616 - // and http.sys behavior: If the Uri contains a query, there must be at least one '/' - // between the authority and the '?' character: It's safe to just look for the first - // '/' after the authority to determine the beginning of the path. - pathStartIndex = uriString.IndexOf('/', authorityStartIndex); - if (pathStartIndex == -1) - { - // e.g. for request lines like: 'GET http://myserver' (no final '/') - pathStartIndex = uriString.Length; - } - } - else - { - // RFC2616: Request-URI = "*" | absoluteURI | abs_path | authority - // 'authority' can only be used with CONNECT which is never received by HttpListener. - // I.e. if we don't have an absolute path (must start with '/') and we don't have - // an absolute Uri (must start with http:// or https://), then 'uriString' must be '*'. - Debug.Assert((uriString.Length == 1) && (uriString[0] == '*'), "Unknown request Uri string format; " - + "Request Uri string is not an absolute Uri, absolute path, or '*': " + uriString); - - // Should we ever get here, be consistent with 2.0/3.5 behavior: just add an initial - // slash to the string and treat it as a path: - uriString = "/" + uriString; - } - } - - // Find end of path: The path is terminated by - // - the first '?' character - // - the first '#' character: This is never the case here, since http.sys won't accept - // Uris containing fragments. Also, RFC2616 doesn't allow fragments in request Uris. - // - end of Uri string - int queryIndex = uriString.IndexOf('?'); - if (queryIndex == -1) - { - queryIndex = uriString.Length; - } - - // will always return a != null string. - return AddSlashToAsteriskOnlyPath(uriString.Substring(pathStartIndex, queryIndex - pathStartIndex)); - } - - private static string AddSlashToAsteriskOnlyPath(string path) - { - Debug.Assert(path != null, "'path' must not be null"); - - // If a request like "OPTIONS * HTTP/1.1" is sent to the listener, then the request Uri - // should be "http[s]://server[:port]/*" to be compatible with pre-4.0 behavior. - if ((path.Length == 1) && (path[0] == '*')) + if (pathInByte.Count == 1 && pathInByte.Array[pathInByte.Offset] == '*') { return "/*"; } - return path; + var unescapedRaw = UrlPathDecoder.Unescape(pathInByte); + return Utf8Encoding.GetString(unescapedRaw.Array, unescapedRaw.Offset, unescapedRaw.Count); } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/UrlInByte.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/UrlInByte.cs new file mode 100644 index 0000000000..ed6ac62126 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/UrlInByte.cs @@ -0,0 +1,123 @@ +using System; +using System.Text; + +namespace Microsoft.Net.Http.Server +{ + internal class UrlInByte + { + private static string HTTP_SCHEME = "http://"; + private static string HTTPS_SCHEME = "https://"; + + private readonly byte[] _raw; + + public UrlInByte(byte[] raw) + { + _raw = raw; + Path = LocalPath(_raw); + } + + public ArraySegment Path { get; } + + /// + /// Find the segment of the URI byte array which represents the path. + /// + private static ArraySegment LocalPath(byte[] raw) + { + // performance + var pathStartIndex = 0; + + // Performance improvement: accept two cases upfront + // + // 1) Since nearly all strings are relative Uris, just look if the string starts with '/'. + // If so, we have a relative Uri and the path starts at position 0. + // (http.sys already trimmed leading whitespaces) + // + // 2) The URL is simply '*' + if (raw[0] != '/' && !(raw.Length == 1 && raw[0] == '*')) + { + // We can't check against cookedUriScheme, since http.sys allows for request http://myserver/ to + // use a request line 'GET https://myserver/' (note http vs. https). Therefore check if the + // Uri starts with either http:// or https://. + var authorityStartIndex = FindHttpOrHttps(raw); + if (authorityStartIndex > 0) + { + // we have an absolute Uri. Find out where the authority ends and the path begins. + // Note that Uris like "http://server?query=value/1/2" are invalid according to RFC2616 + // and http.sys behavior: If the Uri contains a query, there must be at least one '/' + // between the authority and the '?' character: It's safe to just look for the first + // '/' after the authority to determine the beginning of the path. + pathStartIndex = Find(raw, authorityStartIndex, '/'); + if (pathStartIndex == -1) + { + // e.g. for request lines like: 'GET http://myserver' (no final '/') + pathStartIndex = raw.Length; + } + } + else + { + // RFC2616: Request-URI = "*" | absoluteURI | abs_path | authority + // 'authority' can only be used with CONNECT which is never received by HttpListener. + // I.e. if we don't have an absolute path (must start with '/') and we don't have + // an absolute Uri (must start with http:// or https://), then 'uriString' must be '*'. + throw new InvalidOperationException("Invalid URI format"); + } + } + + // Find end of path: The path is terminated by + // - the first '?' character + // - the first '#' character: This is never the case here, since http.sys won't accept + // Uris containing fragments. Also, RFC2616 doesn't allow fragments in request Uris. + // - end of Uri string + var scan = pathStartIndex + 1; + while (scan < raw.Length && raw[scan] != '?') + { + scan++; + } + + return new ArraySegment(raw, pathStartIndex, scan - pathStartIndex); + } + + /// + /// Compare the beginning portion of the raw URL byte array to https:// and http:// + /// + /// The byte array represents the raw URI + /// Length of the matched bytes, 0 if it is not matched. + private static int FindHttpOrHttps(byte[] raw) + { + if (raw.Length < 7) + { + return 0; + } + + if (string.Equals(HTTP_SCHEME, Encoding.UTF8.GetString(raw, 0, 7), StringComparison.OrdinalIgnoreCase)) + { + return 7; + } + + if (raw.Length < 8) + { + return 0; + } + + if (string.Equals(HTTPS_SCHEME, Encoding.UTF8.GetString(raw, 0, 8), StringComparison.OrdinalIgnoreCase)) + { + return 8; + } + + return 0; + } + + private static int Find(byte[] raw, int begin, char target) + { + for (var idx = begin; idx < raw.Length; ++idx) + { + if (raw[idx] == target) + { + return idx; + } + } + + return -1; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/UrlPathDecoder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/UrlPathDecoder.cs new file mode 100644 index 0000000000..7086029810 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/UrlPathDecoder.cs @@ -0,0 +1,313 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.Net.Http.Server +{ + public class UrlPathDecoder + { + /// + /// Unescape a given path string which may contain escaped char. + /// + /// The raw path string to be unescaped + /// The unescaped path string + public static ArraySegment Unescape(ArraySegment rawPath) + { + // the slot to read the input + var reader = rawPath.Offset; + + // the slot to write the unescaped byte + var writer = rawPath.Offset; + + // the end of the path + var end = rawPath.Offset + rawPath.Count; + + // the byte array + var buffer = rawPath.Array; + + while (true) + { + if (reader == end) + { + break; + } + + if (rawPath.Array[reader] == '%') + { + var decodeReader = reader; + + // If decoding process succeeds, the writer iterator will be moved + // to the next write-ready location. On the other hand if the scanned + // percent-encodings cannot be interpreted as sequence of UTF-8 octets, + // these bytes should be copied to output as is. + // The decodeReader iterator is always moved to the first byte not yet + // be scanned after the process. A failed decoding means the chars + // between the reader and decodeReader can be copied to output untouched. + if (!DecodeCore(ref decodeReader, ref writer, end, buffer)) + { + Copy(reader, decodeReader, ref writer, buffer); + } + + reader = decodeReader; + } + else + { + buffer[writer++] = buffer[reader++]; + } + } + + return new ArraySegment(buffer, rawPath.Offset, writer - rawPath.Offset); + } + + /// + /// Unescape the percent-encodings + /// + /// The iterator point to the first % char + /// The place to write to + /// The byte array + private static bool DecodeCore(ref int reader, ref int writer, int end, byte[] buffer) + { + // preserves the original head. if the percent-encodings cannot be interpreted as sequence of UTF-8 octets, + // bytes from this till the last scanned one will be copied to the memory pointed by writer. + var byte1 = UnescapePercentEncoding(ref reader, end, buffer); + + if (byte1 == 0) + { + throw new InvalidOperationException("The path contains null characters."); + } + + if (byte1 == -1) + { + return false; + } + + if (byte1 <= 0x7F) + { + // first byte < U+007f, it is a single byte ASCII + buffer[writer++] = (byte)byte1; + return true; + } + + int byte2 = 0, byte3 = 0, byte4 = 0; + + // anticipate more bytes + var currentDecodeBits = 0; + var byteCount = 1; + var expectValueMin = 0; + if ((byte1 & 0xE0) == 0xC0) + { + // 110x xxxx, expect one more byte + currentDecodeBits = byte1 & 0x1F; + byteCount = 2; + expectValueMin = 0x80; + } + else if ((byte1 & 0xF0) == 0xE0) + { + // 1110 xxxx, expect two more bytes + currentDecodeBits = byte1 & 0x0F; + byteCount = 3; + expectValueMin = 0x800; + } + else if ((byte1 & 0xF8) == 0xF0) + { + // 1111 0xxx, expect three more bytes + currentDecodeBits = byte1 & 0x07; + byteCount = 4; + expectValueMin = 0x10000; + } + else + { + // invalid first byte + return false; + } + + var remainingBytes = byteCount - 1; + while (remainingBytes > 0) + { + // read following three chars + if (reader == buffer.Length) + { + return false; + } + + var nextItr = reader; + var nextByte = UnescapePercentEncoding(ref nextItr, end, buffer); + if (nextByte == -1) + { + return false; + } + + if ((nextByte & 0xC0) != 0x80) + { + // the follow up byte is not in form of 10xx xxxx + return false; + } + + currentDecodeBits = (currentDecodeBits << 6) | (nextByte & 0x3F); + remainingBytes--; + + if (remainingBytes == 1 && currentDecodeBits >= 0x360 && currentDecodeBits <= 0x37F) + { + // this is going to end up in the range of 0xD800-0xDFFF UTF-16 surrogates that + // are not allowed in UTF-8; + return false; + } + + if (remainingBytes == 2 && currentDecodeBits >= 0x110) + { + // this is going to be out of the upper Unicode bound 0x10FFFF. + return false; + } + + reader = nextItr; + if (byteCount - remainingBytes == 2) + { + byte2 = nextByte; + } + else if (byteCount - remainingBytes == 3) + { + byte3 = nextByte; + } + else if (byteCount - remainingBytes == 4) + { + byte4 = nextByte; + } + } + + if (currentDecodeBits < expectValueMin) + { + // overlong encoding (e.g. using 2 bytes to encode something that only needed 1). + return false; + } + + // all bytes are verified, write to the output + if (byteCount > 0) + { + buffer[writer++] = (byte)byte1; + } + if (byteCount > 1) + { + buffer[writer++] = (byte)byte2; + } + if (byteCount > 2) + { + buffer[writer++] = (byte)byte3; + } + if (byteCount > 3) + { + buffer[writer++] = (byte)byte4; + } + + return true; + } + + private static void Copy(int begin, int end, ref int writer, byte[] buffer) + { + while (begin != end) + { + buffer[writer++] = buffer[begin++]; + } + } + + /// + /// Read the percent-encoding and try unescape it. + /// + /// The operation first peek at the character the + /// iterator points at. If it is % the is then + /// moved on to scan the following to characters. If the two following + /// characters are hexadecimal literals they will be unescaped and the + /// value will be returned. + /// + /// If the first character is not % the iterator + /// will be removed beyond the location of % and -1 will be returned. + /// + /// If the following two characters can't be successfully unescaped the + /// iterator will be move behind the % and -1 + /// will be returned. + /// + /// The value to read + /// The byte array + /// The unescaped byte if success. Otherwise return -1. + private static int UnescapePercentEncoding(ref int scan, int end, byte[] buffer) + { + if (buffer[scan++] != '%') + { + return -1; + } + + var probe = scan; + + int value1 = ReadHex(ref probe, end, buffer); + if (value1 == -1) + { + return -1; + } + + int value2 = ReadHex(ref probe, end, buffer); + if (value2 == -1) + { + return -1; + } + + if (SkipUnescape(value1, value2)) + { + return -1; + } + + scan = probe; + return (value1 << 4) + value2; + } + + /// + /// Read the next char and convert it into hexadecimal value. + /// + /// The iterator will be moved to the next + /// byte no matter no matter whether the operation successes. + /// + /// The value to read + /// The byte array + /// The hexadecimal value if successes, otherwise -1. + private static int ReadHex(ref int scan, int end, byte[] buffer) + { + if (scan == end) + { + return -1; + } + + var value = buffer[scan++]; + var isHead = (((value >= '0') && (value <= '9')) || + ((value >= 'A') && (value <= 'F')) || + ((value >= 'a') && (value <= 'f'))); + + if (!isHead) + { + return -1; + } + + if (value <= '9') + { + return value - '0'; + } + else if (value <= 'F') + { + return (value - 'A') + 10; + } + else // a - f + { + return (value - 'a') + 10; + } + } + + private static bool SkipUnescape(int value1, int value2) + { + // skip %2F + if (value1 == 2 && value2 == 15) + { + return true; + } + + return false; + } + } +} diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index 0807e0cc5e..2efcfffcb7 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -324,36 +324,33 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - // This test case ensures the consistency of current server behavior through it is not - // an idea one. [Theory] // Overlong ASCII - [InlineData("%C0%A4", true, HttpStatusCode.OK)] - [InlineData("%C1%BF", true, HttpStatusCode.OK)] - [InlineData("%E0%80%AF", true, HttpStatusCode.OK)] - [InlineData("%E0%9F%BF", true, HttpStatusCode.OK)] - [InlineData("%F0%80%80%AF", true, HttpStatusCode.OK)] - [InlineData("%F0%8F%8F%BF", false, HttpStatusCode.BadRequest)] + [InlineData("%C0%A4", "%C0%A4")] + [InlineData("%C1%BF", "%C1%BF")] + [InlineData("%E0%80%AF", "%E0%80%AF")] + [InlineData("%E0%9F%BF", "%E0%9F%BF")] + [InlineData("%F0%80%80%AF", "%F0%80%80%AF")] + //[InlineData("%F0%8F%8F%BF", "%F0%8F%8F%BF")] // Mixed - [InlineData("%C0%A4%32", true, HttpStatusCode.OK)] - [InlineData("%32%C0%A4%32", true, HttpStatusCode.OK)] - [InlineData("%C0%32%A4", true, HttpStatusCode.OK)] - public async Task Request_ServerErrorFromInvalidUTF8(string requestPath, bool unescaped, HttpStatusCode expectStatus) + [InlineData("%C0%A4%32", "%C0%A42")] + [InlineData("%32%C0%A4%32", "2%C0%A42")] + [InlineData("%C0%32%A4", "%C02%A4")] + public async Task Request_ServerErrorFromInvalidUTF8(string requestPath, string expectedPath) { - bool pathIsUnescaped = false; string root; using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => { var actualPath = httpContext.Request.Path.Value.TrimStart('/'); - pathIsUnescaped = !string.Equals(actualPath, requestPath, StringComparison.Ordinal); + Assert.Equal(expectedPath, actualPath); + return Task.FromResult(0); })) { using (var client = new HttpClient()) { var response = await client.GetAsync(root + "/" + requestPath); - Assert.Equal(expectStatus, response.StatusCode); - Assert.Equal(unescaped, pathIsUnescaped); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } } From b99f98dffb0036573f321777be01adb35e711212 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Sat, 3 Sep 2016 16:47:38 -0700 Subject: [PATCH 396/597] Improve URL path decoding and unescaping components 1. Rename UrlInByte to RawUrlHelper and conver it to static class. 2. Combine UrlPathDecoder and RequestUrlBuilder and convert the latter to a static utility class. --- .../{UrlInByte.cs => RawUrlHelper.cs} | 88 +++-- .../RequestProcessing/Request.cs | 4 +- .../RequestProcessing/RequestUriBuilder.cs | 346 ++++++++++++++++-- .../RequestProcessing/UrlPathDecoder.cs | 313 ---------------- 4 files changed, 386 insertions(+), 365 deletions(-) rename src/Microsoft.Net.Http.Server/RequestProcessing/{UrlInByte.cs => RawUrlHelper.cs} (66%) delete mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/UrlPathDecoder.cs diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/UrlInByte.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs similarity index 66% rename from src/Microsoft.Net.Http.Server/RequestProcessing/UrlInByte.cs rename to src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs index ed6ac62126..0d7d194851 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/UrlInByte.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs @@ -1,27 +1,36 @@ -using System; -using System.Text; +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +// ----------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ----------------------------------------------------------------------- + +using System; namespace Microsoft.Net.Http.Server { - internal class UrlInByte + internal static class RawUrlHelper { - private static string HTTP_SCHEME = "http://"; - private static string HTTPS_SCHEME = "https://"; - - private readonly byte[] _raw; - - public UrlInByte(byte[] raw) - { - _raw = raw; - Path = LocalPath(_raw); - } - - public ArraySegment Path { get; } - /// /// Find the segment of the URI byte array which represents the path. /// - private static ArraySegment LocalPath(byte[] raw) + public static ArraySegment GetPath(byte[] raw) { // performance var pathStartIndex = 0; @@ -84,27 +93,52 @@ namespace Microsoft.Net.Http.Server /// Length of the matched bytes, 0 if it is not matched. private static int FindHttpOrHttps(byte[] raw) { - if (raw.Length < 7) + if (raw[0] != 'h' && raw[0] != 'H') { return 0; } - if (string.Equals(HTTP_SCHEME, Encoding.UTF8.GetString(raw, 0, 7), StringComparison.OrdinalIgnoreCase)) - { - return 7; - } - - if (raw.Length < 8) + if (raw[1] != 't' && raw[1] != 'T') { return 0; } - if (string.Equals(HTTPS_SCHEME, Encoding.UTF8.GetString(raw, 0, 8), StringComparison.OrdinalIgnoreCase)) + if (raw[2] != 't' && raw[2] != 'T') { - return 8; + return 0; } - return 0; + if (raw[3] != 'p' && raw[3] != 'P') + { + return 0; + } + + if (raw[4] == ':') + { + if (raw[5] != '/' || raw[6] != '/') + { + return 0; + } + else + { + return 7; + } + } + else if (raw[4] == 's' || raw[4] == 'S') + { + if (raw[5] != ':' || raw[6] != '/' || raw[7] != '/') + { + return 0; + } + else + { + return 8; + } + } + else + { + return 0; + } } private static int Find(byte[] raw, int begin, char target) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index 3063d777fc..c244a44753 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -72,7 +72,7 @@ namespace Microsoft.Net.Http.Server var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)nativeRequestContext.UrlContext); var rawUrlInBytes = _nativeRequestContext.GetRawUrlInBytes(); - var originalPath = RequestUriBuilder.GetRequestPath(rawUrlInBytes, RequestContext.Logger); + var originalPath = RequestUriBuilder.DecodeAndUnescapePath(rawUrlInBytes); // 'OPTIONS * HTTP/1.1' if (KnownMethod == HttpApi.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal)) @@ -179,7 +179,7 @@ namespace Microsoft.Net.Http.Server public string Path { get; } public bool IsHttps => SslStatus != SslStatus.Insecure; - + public string RawUrl { get; } public Version ProtocolVersion { get; } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 72f76068d1..ce148f0cae 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. +// Copyright (c) Microsoft Open Technologies, Inc. // All Rights Reserved // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,9 +21,8 @@ // // ----------------------------------------------------------------------- -using System.Diagnostics; +using System; using System.Text; -using Microsoft.Extensions.Logging; namespace Microsoft.Net.Http.Server { @@ -31,32 +30,333 @@ namespace Microsoft.Net.Http.Server // we also can't just use the raw Uri, since http.sys supports not only UTF-8, but also ANSI/DBCS and // Unicode code points. System.Uri only supports UTF-8. // The purpose of this class is to decode all UTF-8 percent encoded characters, with the - // exception of %2F ('/'), which is left encoded. - internal sealed class RequestUriBuilder + // exception of %2F ('/'), which is left encoded + internal static class RequestUriBuilder { - private static readonly Encoding Utf8Encoding; + private static readonly Encoding UTF8 = new UTF8Encoding( + encoderShouldEmitUTF8Identifier: false, + throwOnInvalidBytes: true); - static RequestUriBuilder() + public static string DecodeAndUnescapePath(byte[] urlInBytes) { - Utf8Encoding = new UTF8Encoding(false, true); - } - - // Process only the path. - public static string GetRequestPath(byte[] rawUriInBytes, ILogger logger) - { - //Debug.Assert(rawUriInBytes == null || rawUriInBytes.Length == 0, "Empty raw URL."); - //Debug.Assert(logger != null, "Null logger."); - - var rawUriInByte = new UrlInByte(rawUriInBytes); - var pathInByte = rawUriInByte.Path; - - if (pathInByte.Count == 1 && pathInByte.Array[pathInByte.Offset] == '*') + if (urlInBytes == null) { - return "/*"; + throw new ArgumentNullException(nameof(urlInBytes)); } - var unescapedRaw = UrlPathDecoder.Unescape(pathInByte); - return Utf8Encoding.GetString(unescapedRaw.Array, unescapedRaw.Offset, unescapedRaw.Count); + if (urlInBytes.Length == 0) + { + throw new ArgumentException("Length of the URL cannot be zero.", nameof(urlInBytes)); + } + + var rawPath = RawUrlHelper.GetPath(urlInBytes); + + var unescapedPath = Unescape(rawPath); + + return UTF8.GetString(unescapedPath.Array, unescapedPath.Offset, unescapedPath.Count); + } + + /// + /// Unescape a given path string which may contain escaped char. + /// + /// The raw path string to be unescaped + /// The unescaped path string + private static ArraySegment Unescape(ArraySegment rawPath) + { + // the slot to read the input + var reader = rawPath.Offset; + + // the slot to write the unescaped byte + var writer = rawPath.Offset; + + // the end of the path + var end = rawPath.Offset + rawPath.Count; + + // the byte array + var buffer = rawPath.Array; + + while (true) + { + if (reader == end) + { + break; + } + + if (rawPath.Array[reader] == '%') + { + var decodeReader = reader; + + // If decoding process succeeds, the writer iterator will be moved + // to the next write-ready location. On the other hand if the scanned + // percent-encodings cannot be interpreted as sequence of UTF-8 octets, + // these bytes should be copied to output as is. + // The decodeReader iterator is always moved to the first byte not yet + // be scanned after the process. A failed decoding means the chars + // between the reader and decodeReader can be copied to output untouched. + if (!DecodeCore(ref decodeReader, ref writer, end, buffer)) + { + Copy(reader, decodeReader, ref writer, buffer); + } + + reader = decodeReader; + } + else + { + buffer[writer++] = buffer[reader++]; + } + } + + return new ArraySegment(buffer, rawPath.Offset, writer - rawPath.Offset); + } + + /// + /// Unescape the percent-encodings + /// + /// The iterator point to the first % char + /// The place to write to + /// The byte array + private static bool DecodeCore(ref int reader, ref int writer, int end, byte[] buffer) + { + // preserves the original head. if the percent-encodings cannot be interpreted as sequence of UTF-8 octets, + // bytes from this till the last scanned one will be copied to the memory pointed by writer. + var byte1 = UnescapePercentEncoding(ref reader, end, buffer); + + if (byte1 == 0) + { + throw new InvalidOperationException("The path contains null characters."); + } + + if (byte1 == -1) + { + return false; + } + + if (byte1 <= 0x7F) + { + // first byte < U+007f, it is a single byte ASCII + buffer[writer++] = (byte)byte1; + return true; + } + + int byte2 = 0, byte3 = 0, byte4 = 0; + + // anticipate more bytes + var currentDecodeBits = 0; + var byteCount = 1; + var expectValueMin = 0; + if ((byte1 & 0xE0) == 0xC0) + { + // 110x xxxx, expect one more byte + currentDecodeBits = byte1 & 0x1F; + byteCount = 2; + expectValueMin = 0x80; + } + else if ((byte1 & 0xF0) == 0xE0) + { + // 1110 xxxx, expect two more bytes + currentDecodeBits = byte1 & 0x0F; + byteCount = 3; + expectValueMin = 0x800; + } + else if ((byte1 & 0xF8) == 0xF0) + { + // 1111 0xxx, expect three more bytes + currentDecodeBits = byte1 & 0x07; + byteCount = 4; + expectValueMin = 0x10000; + } + else + { + // invalid first byte + return false; + } + + var remainingBytes = byteCount - 1; + while (remainingBytes > 0) + { + // read following three chars + if (reader == buffer.Length) + { + return false; + } + + var nextItr = reader; + var nextByte = UnescapePercentEncoding(ref nextItr, end, buffer); + if (nextByte == -1) + { + return false; + } + + if ((nextByte & 0xC0) != 0x80) + { + // the follow up byte is not in form of 10xx xxxx + return false; + } + + currentDecodeBits = (currentDecodeBits << 6) | (nextByte & 0x3F); + remainingBytes--; + + if (remainingBytes == 1 && currentDecodeBits >= 0x360 && currentDecodeBits <= 0x37F) + { + // this is going to end up in the range of 0xD800-0xDFFF UTF-16 surrogates that + // are not allowed in UTF-8; + return false; + } + + if (remainingBytes == 2 && currentDecodeBits >= 0x110) + { + // this is going to be out of the upper Unicode bound 0x10FFFF. + return false; + } + + reader = nextItr; + if (byteCount - remainingBytes == 2) + { + byte2 = nextByte; + } + else if (byteCount - remainingBytes == 3) + { + byte3 = nextByte; + } + else if (byteCount - remainingBytes == 4) + { + byte4 = nextByte; + } + } + + if (currentDecodeBits < expectValueMin) + { + // overlong encoding (e.g. using 2 bytes to encode something that only needed 1). + return false; + } + + // all bytes are verified, write to the output + if (byteCount > 0) + { + buffer[writer++] = (byte)byte1; + } + if (byteCount > 1) + { + buffer[writer++] = (byte)byte2; + } + if (byteCount > 2) + { + buffer[writer++] = (byte)byte3; + } + if (byteCount > 3) + { + buffer[writer++] = (byte)byte4; + } + + return true; + } + + private static void Copy(int begin, int end, ref int writer, byte[] buffer) + { + while (begin != end) + { + buffer[writer++] = buffer[begin++]; + } + } + + /// + /// Read the percent-encoding and try unescape it. + /// + /// The operation first peek at the character the + /// iterator points at. If it is % the is then + /// moved on to scan the following to characters. If the two following + /// characters are hexadecimal literals they will be unescaped and the + /// value will be returned. + /// + /// If the first character is not % the iterator + /// will be removed beyond the location of % and -1 will be returned. + /// + /// If the following two characters can't be successfully unescaped the + /// iterator will be move behind the % and -1 + /// will be returned. + /// + /// The value to read + /// The byte array + /// The unescaped byte if success. Otherwise return -1. + private static int UnescapePercentEncoding(ref int scan, int end, byte[] buffer) + { + if (buffer[scan++] != '%') + { + return -1; + } + + var probe = scan; + + int value1 = ReadHex(ref probe, end, buffer); + if (value1 == -1) + { + return -1; + } + + int value2 = ReadHex(ref probe, end, buffer); + if (value2 == -1) + { + return -1; + } + + if (SkipUnescape(value1, value2)) + { + return -1; + } + + scan = probe; + return (value1 << 4) + value2; + } + + /// + /// Read the next char and convert it into hexadecimal value. + /// + /// The iterator will be moved to the next + /// byte no matter no matter whether the operation successes. + /// + /// The value to read + /// The byte array + /// The hexadecimal value if successes, otherwise -1. + private static int ReadHex(ref int scan, int end, byte[] buffer) + { + if (scan == end) + { + return -1; + } + + var value = buffer[scan++]; + var isHead = (((value >= '0') && (value <= '9')) || + ((value >= 'A') && (value <= 'F')) || + ((value >= 'a') && (value <= 'f'))); + + if (!isHead) + { + return -1; + } + + if (value <= '9') + { + return value - '0'; + } + else if (value <= 'F') + { + return (value - 'A') + 10; + } + else // a - f + { + return (value - 'a') + 10; + } + } + + private static bool SkipUnescape(int value1, int value2) + { + // skip %2F + if (value1 == 2 && value2 == 15) + { + return true; + } + + return false; } } } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/UrlPathDecoder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/UrlPathDecoder.cs deleted file mode 100644 index 7086029810..0000000000 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/UrlPathDecoder.cs +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.Net.Http.Server -{ - public class UrlPathDecoder - { - /// - /// Unescape a given path string which may contain escaped char. - /// - /// The raw path string to be unescaped - /// The unescaped path string - public static ArraySegment Unescape(ArraySegment rawPath) - { - // the slot to read the input - var reader = rawPath.Offset; - - // the slot to write the unescaped byte - var writer = rawPath.Offset; - - // the end of the path - var end = rawPath.Offset + rawPath.Count; - - // the byte array - var buffer = rawPath.Array; - - while (true) - { - if (reader == end) - { - break; - } - - if (rawPath.Array[reader] == '%') - { - var decodeReader = reader; - - // If decoding process succeeds, the writer iterator will be moved - // to the next write-ready location. On the other hand if the scanned - // percent-encodings cannot be interpreted as sequence of UTF-8 octets, - // these bytes should be copied to output as is. - // The decodeReader iterator is always moved to the first byte not yet - // be scanned after the process. A failed decoding means the chars - // between the reader and decodeReader can be copied to output untouched. - if (!DecodeCore(ref decodeReader, ref writer, end, buffer)) - { - Copy(reader, decodeReader, ref writer, buffer); - } - - reader = decodeReader; - } - else - { - buffer[writer++] = buffer[reader++]; - } - } - - return new ArraySegment(buffer, rawPath.Offset, writer - rawPath.Offset); - } - - /// - /// Unescape the percent-encodings - /// - /// The iterator point to the first % char - /// The place to write to - /// The byte array - private static bool DecodeCore(ref int reader, ref int writer, int end, byte[] buffer) - { - // preserves the original head. if the percent-encodings cannot be interpreted as sequence of UTF-8 octets, - // bytes from this till the last scanned one will be copied to the memory pointed by writer. - var byte1 = UnescapePercentEncoding(ref reader, end, buffer); - - if (byte1 == 0) - { - throw new InvalidOperationException("The path contains null characters."); - } - - if (byte1 == -1) - { - return false; - } - - if (byte1 <= 0x7F) - { - // first byte < U+007f, it is a single byte ASCII - buffer[writer++] = (byte)byte1; - return true; - } - - int byte2 = 0, byte3 = 0, byte4 = 0; - - // anticipate more bytes - var currentDecodeBits = 0; - var byteCount = 1; - var expectValueMin = 0; - if ((byte1 & 0xE0) == 0xC0) - { - // 110x xxxx, expect one more byte - currentDecodeBits = byte1 & 0x1F; - byteCount = 2; - expectValueMin = 0x80; - } - else if ((byte1 & 0xF0) == 0xE0) - { - // 1110 xxxx, expect two more bytes - currentDecodeBits = byte1 & 0x0F; - byteCount = 3; - expectValueMin = 0x800; - } - else if ((byte1 & 0xF8) == 0xF0) - { - // 1111 0xxx, expect three more bytes - currentDecodeBits = byte1 & 0x07; - byteCount = 4; - expectValueMin = 0x10000; - } - else - { - // invalid first byte - return false; - } - - var remainingBytes = byteCount - 1; - while (remainingBytes > 0) - { - // read following three chars - if (reader == buffer.Length) - { - return false; - } - - var nextItr = reader; - var nextByte = UnescapePercentEncoding(ref nextItr, end, buffer); - if (nextByte == -1) - { - return false; - } - - if ((nextByte & 0xC0) != 0x80) - { - // the follow up byte is not in form of 10xx xxxx - return false; - } - - currentDecodeBits = (currentDecodeBits << 6) | (nextByte & 0x3F); - remainingBytes--; - - if (remainingBytes == 1 && currentDecodeBits >= 0x360 && currentDecodeBits <= 0x37F) - { - // this is going to end up in the range of 0xD800-0xDFFF UTF-16 surrogates that - // are not allowed in UTF-8; - return false; - } - - if (remainingBytes == 2 && currentDecodeBits >= 0x110) - { - // this is going to be out of the upper Unicode bound 0x10FFFF. - return false; - } - - reader = nextItr; - if (byteCount - remainingBytes == 2) - { - byte2 = nextByte; - } - else if (byteCount - remainingBytes == 3) - { - byte3 = nextByte; - } - else if (byteCount - remainingBytes == 4) - { - byte4 = nextByte; - } - } - - if (currentDecodeBits < expectValueMin) - { - // overlong encoding (e.g. using 2 bytes to encode something that only needed 1). - return false; - } - - // all bytes are verified, write to the output - if (byteCount > 0) - { - buffer[writer++] = (byte)byte1; - } - if (byteCount > 1) - { - buffer[writer++] = (byte)byte2; - } - if (byteCount > 2) - { - buffer[writer++] = (byte)byte3; - } - if (byteCount > 3) - { - buffer[writer++] = (byte)byte4; - } - - return true; - } - - private static void Copy(int begin, int end, ref int writer, byte[] buffer) - { - while (begin != end) - { - buffer[writer++] = buffer[begin++]; - } - } - - /// - /// Read the percent-encoding and try unescape it. - /// - /// The operation first peek at the character the - /// iterator points at. If it is % the is then - /// moved on to scan the following to characters. If the two following - /// characters are hexadecimal literals they will be unescaped and the - /// value will be returned. - /// - /// If the first character is not % the iterator - /// will be removed beyond the location of % and -1 will be returned. - /// - /// If the following two characters can't be successfully unescaped the - /// iterator will be move behind the % and -1 - /// will be returned. - /// - /// The value to read - /// The byte array - /// The unescaped byte if success. Otherwise return -1. - private static int UnescapePercentEncoding(ref int scan, int end, byte[] buffer) - { - if (buffer[scan++] != '%') - { - return -1; - } - - var probe = scan; - - int value1 = ReadHex(ref probe, end, buffer); - if (value1 == -1) - { - return -1; - } - - int value2 = ReadHex(ref probe, end, buffer); - if (value2 == -1) - { - return -1; - } - - if (SkipUnescape(value1, value2)) - { - return -1; - } - - scan = probe; - return (value1 << 4) + value2; - } - - /// - /// Read the next char and convert it into hexadecimal value. - /// - /// The iterator will be moved to the next - /// byte no matter no matter whether the operation successes. - /// - /// The value to read - /// The byte array - /// The hexadecimal value if successes, otherwise -1. - private static int ReadHex(ref int scan, int end, byte[] buffer) - { - if (scan == end) - { - return -1; - } - - var value = buffer[scan++]; - var isHead = (((value >= '0') && (value <= '9')) || - ((value >= 'A') && (value <= 'F')) || - ((value >= 'a') && (value <= 'f'))); - - if (!isHead) - { - return -1; - } - - if (value <= '9') - { - return value - '0'; - } - else if (value <= 'F') - { - return (value - 'A') + 10; - } - else // a - f - { - return (value - 'a') + 10; - } - } - - private static bool SkipUnescape(int value1, int value2) - { - // skip %2F - if (value1 == 2 && value2 == 15) - { - return true; - } - - return false; - } - } -} From 35429bd91f84fe6c45e3264e6bffb24dde8286da Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 6 Sep 2016 10:34:31 -0700 Subject: [PATCH 397/597] Update overlong UTF8 test case --- .../RequestTests.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index 2efcfffcb7..58f4b6739e 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -331,7 +331,7 @@ namespace Microsoft.AspNetCore.Server.WebListener [InlineData("%E0%80%AF", "%E0%80%AF")] [InlineData("%E0%9F%BF", "%E0%9F%BF")] [InlineData("%F0%80%80%AF", "%F0%80%80%AF")] - //[InlineData("%F0%8F%8F%BF", "%F0%8F%8F%BF")] + [InlineData("%F0%80%BF%BF", "%F0%80%BF%BF")] // Mixed [InlineData("%C0%A4%32", "%C0%A42")] [InlineData("%32%C0%A4%32", "2%C0%A42")] @@ -355,6 +355,20 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + [InlineData("%F0%8F%8F%BF")] + public async Task Request_InvalidCodePointCausesBadRequest(string requestPath) + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => Task.FromResult(0))) + { + using (var client = new HttpClient()) + { + var response = await client.GetAsync(root + "/" + requestPath); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + } + } + [Theory] [InlineData("%2F", "%2F")] [InlineData("foo%2Fbar", "foo%2Fbar")] From 100beaaf949ab732028e9e7e10757b83b49c5f73 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 6 Sep 2016 10:54:26 -0700 Subject: [PATCH 398/597] Add length constrain in path processing --- .../RequestProcessing/NativeRequestContext.cs | 1 - .../RequestProcessing/RawUrlHelper.cs | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index c950358e0c..3c3572a104 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -183,7 +183,6 @@ namespace Microsoft.Net.Http.Server internal byte[] GetRawUrlInBytes() { - if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0) { var result = new byte[NativeRequest->RawUrlLength]; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs index 0d7d194851..4b6b17d637 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs @@ -93,6 +93,11 @@ namespace Microsoft.Net.Http.Server /// Length of the matched bytes, 0 if it is not matched. private static int FindHttpOrHttps(byte[] raw) { + if (raw.Length < 7) + { + return 0; + } + if (raw[0] != 'h' && raw[0] != 'H') { return 0; @@ -126,6 +131,11 @@ namespace Microsoft.Net.Http.Server } else if (raw[4] == 's' || raw[4] == 'S') { + if (raw.Length < 8) + { + return 0; + } + if (raw[5] != ':' || raw[6] != '/' || raw[7] != '/') { return 0; From 93feda2b8a377b2f671522036583d4fac114aa43 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 6 Sep 2016 10:59:04 -0700 Subject: [PATCH 399/597] Rename parameter name in RequestUriBuilder --- .../RequestProcessing/RequestUriBuilder.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index ce148f0cae..df07d502c2 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -37,19 +37,19 @@ namespace Microsoft.Net.Http.Server encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); - public static string DecodeAndUnescapePath(byte[] urlInBytes) + public static string DecodeAndUnescapePath(byte[] rawUrlBytes) { - if (urlInBytes == null) + if (rawUrlBytes == null) { - throw new ArgumentNullException(nameof(urlInBytes)); + throw new ArgumentNullException(nameof(rawUrlBytes)); } - if (urlInBytes.Length == 0) + if (rawUrlBytes.Length == 0) { - throw new ArgumentException("Length of the URL cannot be zero.", nameof(urlInBytes)); + throw new ArgumentException("Length of the URL cannot be zero.", nameof(rawUrlBytes)); } - var rawPath = RawUrlHelper.GetPath(urlInBytes); + var rawPath = RawUrlHelper.GetPath(rawUrlBytes); var unescapedPath = Unescape(rawPath); From 75920860609ef752f110315fd47b2861b57e8080 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 6 Sep 2016 11:01:39 -0700 Subject: [PATCH 400/597] Update comments in RequestUriBuilder --- .../RequestProcessing/RequestUriBuilder.cs | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index df07d502c2..6ca7ff4072 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -57,7 +57,7 @@ namespace Microsoft.Net.Http.Server } /// - /// Unescape a given path string which may contain escaped char. + /// Unescape a given path string in place. The given path string may contain escaped char. /// /// The raw path string to be unescaped /// The unescaped path string @@ -121,16 +121,16 @@ namespace Microsoft.Net.Http.Server // bytes from this till the last scanned one will be copied to the memory pointed by writer. var byte1 = UnescapePercentEncoding(ref reader, end, buffer); + if (!byte1.HasValue) + { + return false; + } + if (byte1 == 0) { throw new InvalidOperationException("The path contains null characters."); } - if (byte1 == -1) - { - return false; - } - if (byte1 <= 0x7F) { // first byte < U+007f, it is a single byte ASCII @@ -147,21 +147,21 @@ namespace Microsoft.Net.Http.Server if ((byte1 & 0xE0) == 0xC0) { // 110x xxxx, expect one more byte - currentDecodeBits = byte1 & 0x1F; + currentDecodeBits = byte1.Value & 0x1F; byteCount = 2; expectValueMin = 0x80; } else if ((byte1 & 0xF0) == 0xE0) { // 1110 xxxx, expect two more bytes - currentDecodeBits = byte1 & 0x0F; + currentDecodeBits = byte1.Value & 0x0F; byteCount = 3; expectValueMin = 0x800; } else if ((byte1 & 0xF8) == 0xF0) { // 1111 0xxx, expect three more bytes - currentDecodeBits = byte1 & 0x07; + currentDecodeBits = byte1.Value & 0x07; byteCount = 4; expectValueMin = 0x10000; } @@ -182,7 +182,7 @@ namespace Microsoft.Net.Http.Server var nextItr = reader; var nextByte = UnescapePercentEncoding(ref nextItr, end, buffer); - if (nextByte == -1) + if (!nextByte.HasValue) { return false; } @@ -193,7 +193,7 @@ namespace Microsoft.Net.Http.Server return false; } - currentDecodeBits = (currentDecodeBits << 6) | (nextByte & 0x3F); + currentDecodeBits = (currentDecodeBits << 6) | (nextByte.Value & 0x3F); remainingBytes--; if (remainingBytes == 1 && currentDecodeBits >= 0x360 && currentDecodeBits <= 0x37F) @@ -212,15 +212,15 @@ namespace Microsoft.Net.Http.Server reader = nextItr; if (byteCount - remainingBytes == 2) { - byte2 = nextByte; + byte2 = nextByte.Value; } else if (byteCount - remainingBytes == 3) { - byte3 = nextByte; + byte3 = nextByte.Value; } else if (byteCount - remainingBytes == 4) { - byte4 = nextByte; + byte4 = nextByte.Value; } } @@ -278,7 +278,7 @@ namespace Microsoft.Net.Http.Server /// The value to read /// The byte array /// The unescaped byte if success. Otherwise return -1. - private static int UnescapePercentEncoding(ref int scan, int end, byte[] buffer) + private static int? UnescapePercentEncoding(ref int scan, int end, byte[] buffer) { if (buffer[scan++] != '%') { @@ -287,25 +287,25 @@ namespace Microsoft.Net.Http.Server var probe = scan; - int value1 = ReadHex(ref probe, end, buffer); - if (value1 == -1) + var value1 = ReadHex(ref probe, end, buffer); + if (!value1.HasValue) { - return -1; + return null; } - int value2 = ReadHex(ref probe, end, buffer); - if (value2 == -1) + var value2 = ReadHex(ref probe, end, buffer); + if (!value2.HasValue) { - return -1; + return null; } - if (SkipUnescape(value1, value2)) + if (SkipUnescape(value1.Value, value2.Value)) { - return -1; + return null; } scan = probe; - return (value1 << 4) + value2; + return (value1.Value << 4) + value2.Value; } /// @@ -317,11 +317,11 @@ namespace Microsoft.Net.Http.Server /// The value to read /// The byte array /// The hexadecimal value if successes, otherwise -1. - private static int ReadHex(ref int scan, int end, byte[] buffer) + private static int? ReadHex(ref int scan, int end, byte[] buffer) { if (scan == end) { - return -1; + return null; } var value = buffer[scan++]; @@ -331,7 +331,7 @@ namespace Microsoft.Net.Http.Server if (!isHead) { - return -1; + return null; } if (value <= '9') @@ -350,7 +350,7 @@ namespace Microsoft.Net.Http.Server private static bool SkipUnescape(int value1, int value2) { - // skip %2F + // skip %2F - '/' if (value1 == 2 && value2 == 15) { return true; From c25d9b68abc21502cd46be37461b674be5ad22b3 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 6 Sep 2016 15:58:08 -0700 Subject: [PATCH 401/597] Use socket in Path encoding and unescaping cases --- .../RequestTests.cs | 135 ------------------ .../RequestTests.cs | 89 ++++++++++++ 2 files changed, 89 insertions(+), 135 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index 58f4b6739e..ce7db01208 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -252,141 +252,6 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] - [InlineData("%D0%A4", "Ф")] - [InlineData("%d0%a4", "Ф")] - [InlineData("%E0%A4%AD", "भ")] - [InlineData("%e0%A4%Ad", "भ")] - [InlineData("%F0%A4%AD%A2", "𤭢")] - [InlineData("%F0%a4%Ad%a2", "𤭢")] - [InlineData("%48%65%6C%6C%6F%20%57%6F%72%6C%64", "Hello World")] - [InlineData("%48%65%6C%6C%6F%2D%C2%B5%40%C3%9F%C3%B6%C3%A4%C3%BC%C3%A0%C3%A1", "Hello-µ@ßöäüàá")] - // Test the borderline cases of overlong UTF8. - [InlineData("%C2%80", "\u0080")] - [InlineData("%E0%A0%80", "\u0800")] - [InlineData("%F0%90%80%80", "\U00010000")] - [InlineData("%63", "c")] - [InlineData("%32", "2")] - [InlineData("%20", " ")] - // Mixed - [InlineData("%%32", "%2")] - [InlineData("%%20", "% ")] - public async Task Request_PathDecodingValidUTF8(string requestPath, string expect) - { - string root; - using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => - { - Assert.Equal(expect, httpContext.Request.Path.Value.TrimStart('/')); - return Task.FromResult(0); - })) - { - var response = await SendRequestAsync(root + "/" + requestPath); - Assert.Equal(string.Empty, response); - } - } - - [Theory] - [InlineData("%C3%84ra%20Benetton", "Ära Benetton")] - [InlineData("%E6%88%91%E8%87%AA%E6%A8%AA%E5%88%80%E5%90%91%E5%A4%A9%E7%AC%91%E5%8E%BB%E7%95%99%E8%82%9D%E8%83%86%E4%B8%A4%E6%98%86%E4%BB%91", "我自横刀向天笑去留肝胆两昆仑")] - public async Task Request_PathDecodingInternationalized(string requestPath, string expect) - { - string root; - using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => - { - Assert.Equal(expect, httpContext.Request.Path.Value.TrimStart('/')); - return Task.FromResult(0); - })) - { - var response = await SendRequestAsync(root + "/" + requestPath); - Assert.Equal(string.Empty, response); - } - } - - [Theory] - // Incomplete - [InlineData("%", "%")] - [InlineData("%%", "%%")] - [InlineData("%A", "%A")] - [InlineData("%Y", "%Y")] - public async Task Request_PathDecodingInvalidUTF8(string requestPath, string expect) - { - string root; - using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => - { - var actualPath = httpContext.Request.Path.Value.TrimStart('/'); - Assert.Equal(expect, actualPath); - - return Task.FromResult(0); - })) - { - var response = await SendRequestAsync(root + "/" + requestPath); - Assert.Equal(string.Empty, response); - } - } - - [Theory] - // Overlong ASCII - [InlineData("%C0%A4", "%C0%A4")] - [InlineData("%C1%BF", "%C1%BF")] - [InlineData("%E0%80%AF", "%E0%80%AF")] - [InlineData("%E0%9F%BF", "%E0%9F%BF")] - [InlineData("%F0%80%80%AF", "%F0%80%80%AF")] - [InlineData("%F0%80%BF%BF", "%F0%80%BF%BF")] - // Mixed - [InlineData("%C0%A4%32", "%C0%A42")] - [InlineData("%32%C0%A4%32", "2%C0%A42")] - [InlineData("%C0%32%A4", "%C02%A4")] - public async Task Request_ServerErrorFromInvalidUTF8(string requestPath, string expectedPath) - { - string root; - using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => - { - var actualPath = httpContext.Request.Path.Value.TrimStart('/'); - Assert.Equal(expectedPath, actualPath); - - return Task.FromResult(0); - })) - { - using (var client = new HttpClient()) - { - var response = await client.GetAsync(root + "/" + requestPath); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - } - } - - [InlineData("%F0%8F%8F%BF")] - public async Task Request_InvalidCodePointCausesBadRequest(string requestPath) - { - string root; - using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => Task.FromResult(0))) - { - using (var client = new HttpClient()) - { - var response = await client.GetAsync(root + "/" + requestPath); - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - } - } - } - - [Theory] - [InlineData("%2F", "%2F")] - [InlineData("foo%2Fbar", "foo%2Fbar")] - [InlineData("foo%2F%20bar", "foo%2F bar")] - public async Task Request_PathDecodingSkipForwardSlash(string requestPath, string expect) - { - string root; - using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext => - { - Assert.Equal(expect, httpContext.Request.Path.Value.TrimStart('/')); - return Task.FromResult(0); - })) - { - var response = await SendRequestAsync(root + "/" + requestPath); - Assert.Equal(string.Empty, response); - } - } - [Fact] public async Task Request_DoubleEscapingAllowed() { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index fa28c81d5b..aa2d76fd29 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -170,6 +170,95 @@ namespace Microsoft.Net.Http.Server } } + [Theory] + [InlineData("%D0%A4", "Ф")] + [InlineData("%d0%a4", "Ф")] + [InlineData("%E0%A4%AD", "भ")] + [InlineData("%e0%A4%Ad", "भ")] + [InlineData("%F0%A4%AD%A2", "𤭢")] + [InlineData("%F0%a4%Ad%a2", "𤭢")] + [InlineData("%48%65%6C%6C%6F%20%57%6F%72%6C%64", "Hello World")] + [InlineData("%48%65%6C%6C%6F%2D%C2%B5%40%C3%9F%C3%B6%C3%A4%C3%BC%C3%A0%C3%A1", "Hello-µ@ßöäüàá")] + // Test the borderline cases of overlong UTF8. + [InlineData("%C2%80", "\u0080")] + [InlineData("%E0%A0%80", "\u0800")] + [InlineData("%F0%90%80%80", "\U00010000")] + [InlineData("%63", "c")] + [InlineData("%32", "2")] + [InlineData("%20", " ")] + // Internationalized + [InlineData("%C3%84ra%20Benetton", "Ära Benetton")] + [InlineData("%E6%88%91%E8%87%AA%E6%A8%AA%E5%88%80%E5%90%91%E5%A4%A9%E7%AC%91%E5%8E%BB%E7%95%99%E8%82%9D%E8%83%86%E4%B8%A4%E6%98%86%E4%BB%91", "我自横刀向天笑去留肝胆两昆仑")] + // Skip forward slash + [InlineData("%2F", "%2F")] + [InlineData("foo%2Fbar", "foo%2Fbar")] + [InlineData("foo%2F%20bar", "foo%2F bar")] + public async Task Request_PathDecodingValidUTF8(string requestPath, string expect) + { + string root; + string actualPath; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) + { + var responseTask = SendSocketRequestAsync(root, "/" + requestPath); + var context = await server.AcceptAsync(); + actualPath = context.Request.Path; + context.Dispose(); + + var response = await responseTask; + Assert.Equal("200", response.Substring(9)); + } + + Assert.Equal(expect, actualPath.TrimStart('/')); + } + + [Theory] + [InlineData("/%%32")] + [InlineData("/%%20")] + [InlineData("/%F0%8F%8F%BF")] + [InlineData("/%")] + [InlineData("/%%")] + [InlineData("/%A")] + [InlineData("/%Y")] + public async Task Request_PathDecodingInvalidUTF8(string requestPath) + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) + { + var responseTask = SendSocketRequestAsync(root, requestPath); + var contextTask = server.AcceptAsync(); + + var response = await responseTask; + Assert.Equal("400", response.Substring(9)); + } + } + + [Theory] + // Overlong ASCII + [InlineData("/%C0%A4", "/%C0%A4")] + [InlineData("/%C1%BF", "/%C1%BF")] + [InlineData("/%E0%80%AF", "/%E0%80%AF")] + [InlineData("/%E0%9F%BF", "/%E0%9F%BF")] + [InlineData("/%F0%80%80%AF", "/%F0%80%80%AF")] + [InlineData("/%F0%80%BF%BF", "/%F0%80%BF%BF")] + // Mixed + [InlineData("/%C0%A4%32", "/%C0%A42")] + [InlineData("/%32%C0%A4%32", "/2%C0%A42")] + [InlineData("/%C0%32%A4", "/%C02%A4")] + public async Task Request_OverlongUTF8Path(string requestPath, string expectedPath) + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) + { + var responseTask = SendSocketRequestAsync(root, requestPath); + var context = await server.AcceptAsync(); + Assert.Equal(expectedPath, context.Request.Path); + context.Dispose(); + + var response = await responseTask; + Assert.Equal("200", response.Substring(9)); + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) From c185082d4098f2c41db5c1c4283bd59c718582f8 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 6 Sep 2016 16:16:23 -0700 Subject: [PATCH 402/597] Update comments in RequestUriBuilder --- .../RequestProcessing/RequestUriBuilder.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 6ca7ff4072..6597bbaf36 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -114,6 +114,7 @@ namespace Microsoft.Net.Http.Server /// /// The iterator point to the first % char /// The place to write to + /// The end of the buffer /// The byte array private static bool DecodeCore(ref int reader, ref int writer, int end, byte[] buffer) { @@ -276,6 +277,7 @@ namespace Microsoft.Net.Http.Server /// will be returned. /// /// The value to read + /// The end of the buffer /// The byte array /// The unescaped byte if success. Otherwise return -1. private static int? UnescapePercentEncoding(ref int scan, int end, byte[] buffer) @@ -315,6 +317,7 @@ namespace Microsoft.Net.Http.Server /// byte no matter no matter whether the operation successes. /// /// The value to read + /// The end of the buffer /// The byte array /// The hexadecimal value if successes, otherwise -1. private static int? ReadHex(ref int scan, int end, byte[] buffer) From 295dab5d505eb939972648704b6d781539fde873 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sun, 4 Sep 2016 19:09:27 -0700 Subject: [PATCH 403/597] Remove .travis.yml file - no reason to build or test Windows-only WebListener on Linux or OS X --- .travis.yml | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index df22f7a880..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: csharp -sudo: required -dist: trusty -addons: - apt: - packages: - - gettext - - libcurl4-openssl-dev - - libicu-dev - - libssl-dev - - libunwind8 - - zlib1g -mono: - - 4.0.5 -os: - - linux - - osx -osx_image: xcode7.1 -branches: - only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ -script: - - ./build.sh verify \ No newline at end of file From a787a01a739a3b907ae7b587be254ccdccbcd1b5 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 6 Sep 2016 12:36:23 -0700 Subject: [PATCH 404/597] Downgrade to 1.0 dependencies --- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- .../project.json | 4 +- src/Microsoft.Net.Http.Server/NullLogger.cs | 51 +++++++++++++++++++ .../WebListenerSettings.cs | 1 - src/Microsoft.Net.Http.Server/project.json | 4 +- .../project.json | 2 +- .../project.json | 2 +- 8 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 src/Microsoft.Net.Http.Server/NullLogger.cs diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index d6538aa090..923b80c29c 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -2,7 +2,7 @@ "version": "1.1.0-*", "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.1.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index f621b8021a..5687132a8e 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,7 @@ { "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.1.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 56cfd2f176..43e21fe3de 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -2,8 +2,8 @@ "version": "0.2.0-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { - "Microsoft.AspNetCore.Hosting": "1.1.0-*", - "Microsoft.Net.Http.Headers": "1.1.0-*", + "Microsoft.AspNetCore.Hosting": "1.0.0", + "Microsoft.Net.Http.Headers": "1.0.0", "Microsoft.Net.Http.Server": "0.2.0-*" }, "buildOptions": { diff --git a/src/Microsoft.Net.Http.Server/NullLogger.cs b/src/Microsoft.Net.Http.Server/NullLogger.cs new file mode 100644 index 0000000000..8e82046da2 --- /dev/null +++ b/src/Microsoft.Net.Http.Server/NullLogger.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Open Technologies, Inc. +// All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF +// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR +// NON-INFRINGEMENT. +// See the Apache 2 License for the specific language governing +// permissions and limitations under the License. + +using System; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Net.Http.Server +{ + internal class NullLogger : ILogger + { + public static readonly NullLogger Instance = new NullLogger(); + + public IDisposable BeginScope(TState state) + { + return NullDisposable.Instance; + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + } + + public bool IsEnabled(LogLevel logLevel) + { + return false; + } + + private class NullDisposable : IDisposable + { + public static readonly NullDisposable Instance = new NullDisposable(); + + public void Dispose() + { + // intentionally does nothing + } + } + } +} diff --git a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs index ce2bd122df..a952137227 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs @@ -17,7 +17,6 @@ using System; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index c7083374f7..91402ad7d9 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -2,8 +2,8 @@ "version": "0.2.0-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Primitives": "1.1.0-*" + "Microsoft.Extensions.Logging.Abstractions": "1.0.0", + "Microsoft.Extensions.Primitives": "1.0.0" }, "buildOptions": { "allowUnsafe": true, diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index d25973f484..0da4448638 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -7,7 +7,7 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", - "Microsoft.AspNetCore.Testing": "1.1.0-*", + "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit": "2.2.0-*" }, "frameworks": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 399d8dc19d..9a0a5948de 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -3,7 +3,7 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.Net.Http.Server": "0.2.0-*", - "Microsoft.AspNetCore.Testing": "1.1.0-*", + "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit": "2.2.0-*" }, "frameworks": { From a526454321d6bdcc5a3ef454c72f6cd76e417813 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 7 Sep 2016 09:55:21 -0700 Subject: [PATCH 405/597] Raise version from 0.2.0-pre to 1.0.0-rc1 --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNetCore.Server.WebListener/project.json | 4 ++-- src/Microsoft.Net.Http.Server/project.json | 2 +- .../project.json | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index b63c18564c..3c539e30a1 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,7 +3,7 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.Net.Http.Server": "0.2.0-*" + "Microsoft.Net.Http.Server": "1.0.0-rc1-*" }, "commands": { "sample": "HelloWorld" diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 923b80c29c..1f960ccef4 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,7 +1,7 @@ { "version": "1.1.0-*", "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "buildOptions": { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 5687132a8e..52c5854dbc 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, "buildOptions": { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 43e21fe3de..dc0d01e50e 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -1,10 +1,10 @@ { - "version": "0.2.0-*", + "version": "1.0.0-rc1-*", "description": "ASP.NET 5 self-host web server.", "dependencies": { "Microsoft.AspNetCore.Hosting": "1.0.0", "Microsoft.Net.Http.Headers": "1.0.0", - "Microsoft.Net.Http.Server": "0.2.0-*" + "Microsoft.Net.Http.Server": "1.0.0-rc1-*" }, "buildOptions": { "allowUnsafe": true, diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 91402ad7d9..57d8bbe8b7 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,5 +1,5 @@ { - "version": "0.2.0-*", + "version": "1.0.0-rc1-*", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "1.0.0", diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 0da4448638..ae72d0619a 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -6,7 +6,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Server.WebListener": "0.2.0-*", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit": "2.2.0-*" }, diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 9a0a5948de..91f6c36ca0 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -2,7 +2,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "0.2.0-*", + "Microsoft.Net.Http.Server": "1.0.0-rc1-*", "Microsoft.AspNetCore.Testing": "1.0.0-*", "xunit": "2.2.0-*" }, From b94519b821f1daec1f9e15cb339e0b8524a44bac Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 7 Sep 2016 10:24:38 -0700 Subject: [PATCH 406/597] Pin versions --- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- .../project.json | 2 +- src/Microsoft.Net.Http.Server/project.json | 32 +++++++++---------- .../project.json | 2 +- .../project.json | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 1f960ccef4..7a8871d4f6 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -2,7 +2,7 @@ "version": "1.1.0-*", "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0" }, "buildOptions": { "emitEntryPoint": true diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 52c5854dbc..8a48d6ac6d 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,7 @@ { "dependencies": { "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", - "Microsoft.Extensions.Logging.Console": "1.0.0-*" + "Microsoft.Extensions.Logging.Console": "1.0.0" }, "buildOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index dc0d01e50e..234a44efd2 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -19,7 +19,7 @@ "net451": {}, "netstandard1.3": { "dependencies": { - "System.Security.Claims": "4.0.1-*" + "System.Security.Claims": "4.0.1" } } } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 57d8bbe8b7..fe3340ff30 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -28,22 +28,22 @@ "type": "build", "version": "1.1.0-*" }, - "Microsoft.Win32.Primitives": "4.0.1-*", - "System.Diagnostics.Contracts": "4.0.1-*", - "System.Diagnostics.Debug": "4.0.11-*", - "System.Diagnostics.Tools": "4.0.1-*", - "System.IO": "4.1.0-*", - "System.IO.FileSystem": "4.0.1-*", - "System.Net.Primitives": "4.0.11-*", - "System.Net.WebSockets": "4.0.0-*", - "System.Runtime.Extensions": "4.1.0-*", - "System.Runtime.InteropServices": "4.1.0-*", - "System.Security.Claims": "4.0.1-*", - "System.Security.Cryptography.X509Certificates": "4.1.0-*", - "System.Security.Principal.Windows": "4.0.0-*", - "System.Text.Encoding.Extensions": "4.0.11-*", - "System.Threading": "4.0.11-*", - "System.Threading.Overlapped": "4.0.1-*", + "Microsoft.Win32.Primitives": "4.0.1", + "System.Diagnostics.Contracts": "4.0.1", + "System.Diagnostics.Debug": "4.0.11", + "System.Diagnostics.Tools": "4.0.1", + "System.IO": "4.1.0", + "System.IO.FileSystem": "4.0.1", + "System.Net.Primitives": "4.0.11", + "System.Net.WebSockets": "4.0.0", + "System.Runtime.Extensions": "4.1.0", + "System.Runtime.InteropServices": "4.1.0", + "System.Security.Claims": "4.0.1", + "System.Security.Cryptography.X509Certificates": "4.1.0", + "System.Security.Principal.Windows": "4.0.0", + "System.Text.Encoding.Extensions": "4.0.11", + "System.Threading": "4.0.11", + "System.Threading.Overlapped": "4.0.1", "System.Threading.Timer": "4.0.1" } } diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index ae72d0619a..14c0131feb 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -7,7 +7,7 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", - "Microsoft.AspNetCore.Testing": "1.0.0-*", + "Microsoft.AspNetCore.Testing": "1.0.0", "xunit": "2.2.0-*" }, "frameworks": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 91f6c36ca0..179757aaf4 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -3,7 +3,7 @@ "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.Net.Http.Server": "1.0.0-rc1-*", - "Microsoft.AspNetCore.Testing": "1.0.0-*", + "Microsoft.AspNetCore.Testing": "1.0.0", "xunit": "2.2.0-*" }, "frameworks": { From e984b89e0a3acd5a2ebc7001ca85b90f14a51b50 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 7 Sep 2016 10:24:56 -0700 Subject: [PATCH 407/597] Switch to master myget feed --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 826a1f9035..9fca4584cc 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@  - + \ No newline at end of file From dc8806f07e0d67e6a47ac3cb59aa1c37b27d4a37 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 7 Sep 2016 11:24:39 -0700 Subject: [PATCH 408/597] Downgrade and pin Microsoft.Extensions.RuntimeEnvironment.Sources --- src/Microsoft.Net.Http.Server/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index fe3340ff30..c23246d6d6 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -26,7 +26,7 @@ "dependencies": { "Microsoft.Extensions.RuntimeEnvironment.Sources": { "type": "build", - "version": "1.1.0-*" + "version": "1.0.0" }, "Microsoft.Win32.Primitives": "4.0.1", "System.Diagnostics.Contracts": "4.0.1", From 7a37091d3b907828b003c8e5fafbf070754106c5 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 8 Sep 2016 10:02:07 -0700 Subject: [PATCH 409/597] Use TaskCache class from Microsoft.Extensions.TaskCache.Sources (#254) Instead of Task.FromResult(0) --- .../AuthenticationHandler.cs | 9 +++++---- .../FeatureContext.cs | 3 ++- src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs | 2 -- src/Microsoft.AspNetCore.Server.WebListener/project.json | 6 +++++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs index bd1df634e9..a2122d457f 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs @@ -26,6 +26,7 @@ using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.Extensions.Internal; using Microsoft.Net.Http.Server; namespace Microsoft.AspNetCore.Server.WebListener @@ -63,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } } - return Task.FromResult(0); + return TaskCache.CompletedTask; } public Task ChallengeAsync(ChallengeContext context) @@ -108,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } // A challenge was issued, it overrides any pre-set auth types. _requestContext.Response.AuthenticationChallenges = _customChallenges; - return Task.FromResult(0); + return TaskCache.CompletedTask; } public void GetDescriptions(DescribeSchemesContext context) @@ -123,13 +124,13 @@ namespace Microsoft.AspNetCore.Server.WebListener public Task SignInAsync(SignInContext context) { // Not supported. AuthenticationManager will throw if !Accepted. - return Task.FromResult(0); + return TaskCache.CompletedTask; } public Task SignOutAsync(SignOutContext context) { // Not supported. AuthenticationManager will throw if !Accepted. - return Task.FromResult(0); + return TaskCache.CompletedTask; } private IDictionary GetDescription(string authenticationScheme) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index 223cf3a9ac..63786ed5d6 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -28,6 +28,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.Extensions.Internal; using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Server; @@ -590,7 +591,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { if (_completed) { - return Helpers.CompletedTask; + return TaskCache.CompletedTask; } _completed = true; return NotifyOnCompletedAsync(); diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs index 1b7efd9698..688b783ff2 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs @@ -28,8 +28,6 @@ namespace Microsoft.AspNetCore.Server.WebListener { internal static class Helpers { - internal static Task CompletedTask { get; } = Task.FromResult(0); - internal static ConfiguredTaskAwaitable SupressContext(this Task task) { return task.ConfigureAwait(continueOnCapturedContext: false); diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 56cfd2f176..1154107020 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -4,7 +4,11 @@ "dependencies": { "Microsoft.AspNetCore.Hosting": "1.1.0-*", "Microsoft.Net.Http.Headers": "1.1.0-*", - "Microsoft.Net.Http.Server": "0.2.0-*" + "Microsoft.Net.Http.Server": "0.2.0-*", + "Microsoft.Extensions.TaskCache.Sources": { + "version": "1.1.0-*", + "type": "build" + } }, "buildOptions": { "allowUnsafe": true, From bc7eb631d93a5bdf3202187b03cb30117678e69a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 8 Sep 2016 14:06:13 -0700 Subject: [PATCH 410/597] Pin to 1.0.0-rc1-final --- samples/HelloWorld/project.json | 4 ++-- samples/HotAddSample/project.json | 4 ++-- samples/SelfHostServer/project.json | 4 ++-- src/Microsoft.AspNetCore.Server.WebListener/project.json | 4 ++-- src/Microsoft.Net.Http.Server/project.json | 2 +- .../project.json | 4 ++-- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 4 ++-- test/Microsoft.Net.Http.Server.Tests/project.json | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 3c539e30a1..e8d088ba9e 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,7 +3,7 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.Net.Http.Server": "1.0.0-rc1-*" + "Microsoft.Net.Http.Server": "1.0.0-rc1-final" }, "commands": { "sample": "HelloWorld" @@ -13,7 +13,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.0.0", "type": "platform" } } diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 7a8871d4f6..f7d3cb30d2 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,7 +1,7 @@ { "version": "1.1.0-*", "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-final", "Microsoft.Extensions.Logging.Console": "1.0.0" }, "buildOptions": { @@ -15,7 +15,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.0.0", "type": "platform" } } diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 8a48d6ac6d..61a41dccf5 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-final", "Microsoft.Extensions.Logging.Console": "1.0.0" }, "buildOptions": { @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.0.0", "type": "platform" } } diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 234a44efd2..27eed10c6b 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -1,10 +1,10 @@ { - "version": "1.0.0-rc1-*", + "version": "1.0.0-rc1-final", "description": "ASP.NET 5 self-host web server.", "dependencies": { "Microsoft.AspNetCore.Hosting": "1.0.0", "Microsoft.Net.Http.Headers": "1.0.0", - "Microsoft.Net.Http.Server": "1.0.0-rc1-*" + "Microsoft.Net.Http.Server": "1.0.0-rc1-final" }, "buildOptions": { "allowUnsafe": true, diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index c23246d6d6..314afcfa67 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-rc1-*", + "version": "1.0.0-rc1-final", "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "1.0.0", diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 14c0131feb..88bf098bd4 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -6,7 +6,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-*", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-final", "Microsoft.AspNetCore.Testing": "1.0.0", "xunit": "2.2.0-*" }, @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.0.0", "type": "platform" }, "System.Net.Http.WinHttpHandler": "4.0.0-*", diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 179757aaf4..bf605d7360 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -2,7 +2,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "1.0.0-rc1-*", + "Microsoft.Net.Http.Server": "1.0.0-rc1-final", "Microsoft.AspNetCore.Testing": "1.0.0", "xunit": "2.2.0-*" }, @@ -10,7 +10,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.0.0", "type": "platform" }, "System.Net.Http": "4.1.0-*", diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index f4d93ce1af..81687ac3a3 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -2,14 +2,14 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "0.2.0-*", + "Microsoft.Net.Http.Server": "1.0.0-rc1-final", "xunit": "2.2.0-*" }, "frameworks": { "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.0.0", "type": "platform" } } From 99a98af51e425dcccc8ce4f5c0549bbb9f6f25bc Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 9 Sep 2016 13:53:15 -0700 Subject: [PATCH 411/597] #229 Update package descriptions and tags --- src/Microsoft.AspNetCore.Server.WebListener/project.json | 8 +++++++- src/Microsoft.Net.Http.Server/project.json | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 27eed10c6b..3641825f52 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -1,6 +1,12 @@ { "version": "1.0.0-rc1-final", - "description": "ASP.NET 5 self-host web server.", + "description": "ASP.NET Core HTTP server for Windows.", + "packOptions": { + "tags": [ + "aspnetcore", + "weblistener" + ] + }, "dependencies": { "Microsoft.AspNetCore.Hosting": "1.0.0", "Microsoft.Net.Http.Headers": "1.0.0", diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 314afcfa67..c194e0a135 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,6 +1,12 @@ { "version": "1.0.0-rc1-final", - "description": "Implementation of WebListener, a successor to HttpListener. It is used in the WebListener server package.", + "description": ".NET HTTP server that uses the Windows HTTP Server API.", + "packOptions": { + "tags": [ + "netcore", + "weblistener" + ] + }, "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "1.0.0", "Microsoft.Extensions.Primitives": "1.0.0" From ba4965155268435cc773282256ac428bd75a9ced Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 9 Sep 2016 15:43:04 -0700 Subject: [PATCH 412/597] Increment version to 1.0.0-rc1-final --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNetCore.Server.WebListener/project.json | 4 ++-- src/Microsoft.Net.Http.Server/project.json | 2 +- .../project.json | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- test/Microsoft.Net.Http.Server.Tests/project.json | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index e8d088ba9e..0188f94723 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,7 +3,7 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.Net.Http.Server": "1.0.0-rc1-final" + "Microsoft.Net.Http.Server": "1.0.0-rc2-final" }, "commands": { "sample": "HelloWorld" diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index f7d3cb30d2..1371305e91 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,7 +1,7 @@ { "version": "1.1.0-*", "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-final", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc2-final", "Microsoft.Extensions.Logging.Console": "1.0.0" }, "buildOptions": { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 61a41dccf5..f33119839b 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-final", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc2-final", "Microsoft.Extensions.Logging.Console": "1.0.0" }, "buildOptions": { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 3641825f52..bdfe64508c 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-rc1-final", + "version": "1.0.0-rc2-final", "description": "ASP.NET Core HTTP server for Windows.", "packOptions": { "tags": [ @@ -10,7 +10,7 @@ "dependencies": { "Microsoft.AspNetCore.Hosting": "1.0.0", "Microsoft.Net.Http.Headers": "1.0.0", - "Microsoft.Net.Http.Server": "1.0.0-rc1-final" + "Microsoft.Net.Http.Server": "1.0.0-rc2-final" }, "buildOptions": { "allowUnsafe": true, diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index c194e0a135..b0b467ba09 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-rc1-final", + "version": "1.0.0-rc2-final", "description": ".NET HTTP server that uses the Windows HTTP Server API.", "packOptions": { "tags": [ diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 88bf098bd4..17449f517c 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -6,7 +6,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc1-final", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc2-final", "Microsoft.AspNetCore.Testing": "1.0.0", "xunit": "2.2.0-*" }, diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index bf605d7360..f69d545db9 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -2,7 +2,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "1.0.0-rc1-final", + "Microsoft.Net.Http.Server": "1.0.0-rc2-final", "Microsoft.AspNetCore.Testing": "1.0.0", "xunit": "2.2.0-*" }, diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index 81687ac3a3..bfdd758b97 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -2,7 +2,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "1.0.0-rc1-final", + "Microsoft.Net.Http.Server": "1.0.0-rc2-final", "xunit": "2.2.0-*" }, "frameworks": { From 7e76ea8731fe19fd4634ee0cd8ad1b426579b458 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 30 Sep 2016 11:44:59 -0700 Subject: [PATCH 413/597] Update file license headers --- .../AuthenticationHandler.cs | 24 +----------- .../FeatureContext.cs | 18 +-------- .../Helpers.cs | 24 +----------- .../Internal/WebListenerOptionsSetup.cs | 18 +-------- .../LogHelper.cs | 24 +----------- .../MessagePump.cs | 18 +-------- .../Properties/AssemblyInfo.cs | 2 +- .../ResponseStream.cs | 24 +----------- .../StandardFeatureCollection.cs | 18 +-------- .../WebHostBuilderWebListenerExtensions.cs | 18 +-------- .../WebListenerOptions.cs | 18 +-------- .../AsyncAcceptContext.cs | 24 +----------- .../AuthenticationManager.cs | 24 +----------- .../AuthenticationSchemes.cs | 18 +-------- src/Microsoft.Net.Http.Server/Constants.cs | 24 +----------- .../GlobalSuppressions.cs | 36 ------------------ src/Microsoft.Net.Http.Server/Helpers.cs | 24 +----------- src/Microsoft.Net.Http.Server/LogHelper.cs | 24 +----------- .../NativeInterop/AddressFamily.cs | 24 +----------- .../NativeInterop/ComNetOS.cs | 24 +----------- .../NativeInterop/ContextAttribute.cs | 24 +----------- .../NativeInterop/CookedUrl.cs | 24 +----------- .../NativeInterop/DisconnectListener.cs | 18 +-------- .../NativeInterop/HeapAllocHandle.cs | 18 +-------- .../NativeInterop/HttpApi.cs | 18 +-------- .../NativeInterop/HttpRequestQueueV2Handle.cs | 24 +----------- .../NativeInterop/HttpServerSessionHandle.cs | 24 +----------- .../NativeInterop/HttpSysRequestHeader.cs | 24 +----------- .../NativeInterop/HttpSysResponseHeader.cs | 24 +----------- .../NativeInterop/HttpSysSettings.cs | 24 +----------- .../NativeInterop/IntPtrHelper.cs | 24 +----------- .../NativeInterop/NclUtilities.cs | 24 +----------- .../NativeInterop/RequestQueue.cs | 18 +-------- .../NativeInterop/SSPIHandle.cs | 24 +----------- .../NativeInterop/SafeLoadLibrary.cs | 24 +----------- .../NativeInterop/SafeLocalFree.cs | 24 +----------- .../SafeLocalFreeChannelBinding.cs | 24 +----------- .../NativeInterop/SafeLocalMemHandle.cs | 24 +----------- .../NativeInterop/SafeNativeOverlapped.cs | 24 +----------- .../NativeInterop/SchProtocols.cs | 24 +----------- .../NativeInterop/SecurityStatus.cs | 24 +----------- .../NativeInterop/ServerSession.cs | 18 +-------- .../NativeInterop/SocketAddress.cs | 24 +----------- .../NativeInterop/TokenBindingUtil.cs | 18 +-------- .../NativeInterop/UnsafeNativeMethods.cs | 24 +----------- .../NativeInterop/UrlGroup.cs | 18 +-------- src/Microsoft.Net.Http.Server/NullLogger.cs | 18 +-------- .../Overlapped/DeferredDisposableLifetime.cs | 3 ++ .../Overlapped/IDeferredDisposable.cs | 3 ++ .../Overlapped/PreAllocatedOverlapped.cs | 3 ++ .../Overlapped/ThreadPoolBoundHandle.cs | 3 ++ .../ThreadPoolBoundHandleOverlapped.cs | 3 ++ .../Properties/AssemblyInfo.cs | 2 +- .../RequestProcessing/BoundaryType.cs | 24 +----------- .../RequestProcessing/ClientCertLoader.cs | 24 +----------- .../RequestProcessing/HeaderCollection.cs | 2 +- .../RequestProcessing/HeaderEncoding.cs | 24 +----------- .../RequestProcessing/HeaderParser.cs | 2 +- .../RequestProcessing/HttpKnownHeaderNames.cs | 24 +----------- .../RequestProcessing/HttpReasonPhrase.cs | 24 +----------- .../RequestProcessing/HttpStatusCode.cs | 24 +----------- .../RequestProcessing/NativeRequestContext.cs | 24 +----------- .../RequestProcessing/OpaqueStream.cs | 24 +----------- .../RequestProcessing/RawUrlHelper.cs | 24 +----------- .../RequestProcessing/Request.cs | 24 +----------- .../RequestProcessing/RequestContext.cs | 24 +----------- .../RequestProcessing/RequestHeaders.cs | 37 +------------------ .../RequestProcessing/RequestStream.cs | 24 +----------- .../RequestStreamAsyncResult.cs | 24 +----------- .../RequestProcessing/RequestUriBuilder.cs | 24 +----------- .../RequestProcessing/Response.cs | 24 +----------- .../RequestProcessing/ResponseStream.cs | 24 +----------- .../ResponseStreamAsyncResult.cs | 24 +----------- .../RequestProcessing/SslStatus.cs | 24 +----------- .../Resources.Designer.cs | 18 +-------- .../TimeoutManager.cs | 24 +----------- src/Microsoft.Net.Http.Server/UrlPrefix.cs | 24 +----------- .../UrlPrefixCollection.cs | 2 +- .../ValidationHelper.cs | 24 +----------- src/Microsoft.Net.Http.Server/WebListener.cs | 24 +----------- .../WebListenerException.cs | 24 +----------- .../WebListenerSettings.cs | 18 +-------- .../WebSocketHelpers.cs | 24 +----------- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 24 +----------- .../SafeHandleZeroOrMinusOneIsInvalid.cs | 24 +----------- .../fx/System/Net/WebSockets/CompatHelpers.cs | 5 ++- .../fx/System/Net/WebSockets/SR.cs | 5 ++- .../AuthenticationTests.cs | 18 +-------- .../DummyApplication.cs | 18 +-------- .../HttpsTests.cs | 18 +-------- .../OpaqueUpgradeTests.cs | 18 +-------- .../RequestBodyTests.cs | 18 +-------- .../RequestHeaderTests.cs | 18 +-------- .../RequestTests.cs | 18 +-------- .../ResponseBodyTests.cs | 18 +-------- .../ResponseCachingTests.cs | 3 +- .../ResponseHeaderTests.cs | 18 +-------- .../ResponseSendFileTests.cs | 18 +-------- .../ResponseTests.cs | 18 +-------- .../ServerTests.cs | 18 +-------- .../Utilities.cs | 18 +-------- .../WebSocketTests.cs | 18 +-------- .../AuthenticationTests.cs | 3 +- .../HttpsTests.cs | 3 +- .../OpaqueUpgradeTests.cs | 3 +- .../RequestBodyTests.cs | 3 +- .../RequestHeaderTests.cs | 3 +- .../RequestTests.cs | 3 +- .../ResponseBodyTests.cs | 3 +- .../ResponseCachingTests.cs | 3 +- .../ResponseHeaderTests.cs | 3 +- .../ResponseSendFileTests.cs | 3 +- .../ResponseTests.cs | 3 +- .../ServerTests.cs | 3 +- .../Utilities.cs | 3 +- .../WebSocketTests.cs | 3 +- 116 files changed, 234 insertions(+), 1821 deletions(-) delete mode 100644 src/Microsoft.Net.Http.Server/GlobalSuppressions.cs diff --git a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs index bd1df634e9..d1617dfd19 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs index 223cf3a9ac..fe46b2d53c 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs index 1b7efd9698..3dbaf24544 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Runtime.CompilerServices; using System.Threading.Tasks; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs b/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs index 6b87fd31ad..b1664c9539 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs index 8ab5feee6e..70a819396b 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs index 3de914ea0d..f88b4f1ff3 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs index 17fae786fd..aff612408a 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Reflection; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs b/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs index d641124c42..d042552106 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs index 1c53ca1055..ce579ab3bb 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs @@ -1,19 +1,5 @@ -// Copyright (c) .NET Foundation. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs index f314cb1c4a..62f1a8d376 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Hosting.Server; diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs b/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs index aa4bbbc0f5..ec3b14f2ab 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs +++ b/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.Net.Http.Server; diff --git a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs index 58a5f7f186..608e46d990 100644 --- a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics.CodeAnalysis; diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs index 14153b285b..31b1b9b35a 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs b/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs index 1f53175cbd..a531724e1c 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs +++ b/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/src/Microsoft.Net.Http.Server/Constants.cs b/src/Microsoft.Net.Http.Server/Constants.cs index 4991637282..866b87d965 100644 --- a/src/Microsoft.Net.Http.Server/Constants.cs +++ b/src/Microsoft.Net.Http.Server/Constants.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/src/Microsoft.Net.Http.Server/GlobalSuppressions.cs b/src/Microsoft.Net.Http.Server/GlobalSuppressions.cs deleted file mode 100644 index 88c4ba087d..0000000000 --- a/src/Microsoft.Net.Http.Server/GlobalSuppressions.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- -// -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. -// -// To add a suppression to this file, right-click the message in the -// Code Analysis results, point to "Suppress Message", and click -// "In Suppression File". -// You do not need to add suppressions to this file manually. - -using System.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification = "Delay signed")] diff --git a/src/Microsoft.Net.Http.Server/Helpers.cs b/src/Microsoft.Net.Http.Server/Helpers.cs index 6d9aaaba0e..fb79443195 100644 --- a/src/Microsoft.Net.Http.Server/Helpers.cs +++ b/src/Microsoft.Net.Http.Server/Helpers.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.CompilerServices; diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs index e96ba71b10..bb8ce05414 100644 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ b/src/Microsoft.Net.Http.Server/LogHelper.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs b/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs index cc7f44b913..d2ebe14509 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs index a4fd732d58..61e02d91c9 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.Extensions.Internal; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs index 2964b40da6..5c1dfed25d 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs b/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs index ed702b7406..f72682869c 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.InteropServices; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs b/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs index e96ed834a6..56bbb02a4b 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Concurrent; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs index e7d24271d9..100ee4333e 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs @@ -1,19 +1,5 @@ -// Copyright (c) .NET Foundation. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.Win32.SafeHandles; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs index 10c736af80..6ba4851852 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs @@ -1,19 +1,5 @@ -// Copyright (c) .NET Foundation. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs index 8b78d4e14a..41c21ec4d6 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.Win32.SafeHandles; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs index 1bdfafb8f7..346351e1a5 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Threading; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs index 436a993cfd..58fadd7aff 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs index 570a7928ea..4e2fd9f0e4 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs index 946345193c..dc2138a256 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs b/src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs index d3594b3deb..f4bbeb7e4e 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs index 7901200e79..16fc5ec4c0 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs b/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs index c650041703..e8cfff4e5f 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.InteropServices; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs index 3c9bf9d67f..33885c2758 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.InteropServices; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs index 7b996d37fa..be7547dc1f 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.Win32.SafeHandles; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs index 886381465b..eed7b8498a 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.Win32.SafeHandles; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs index 8a08e20b85..f2e685f9e3 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Security.Authentication.ExtendedProtection; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs index d961d1d38b..e367283c19 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.Win32.SafeHandles; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs index e1c2709a3e..70f83b09ea 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.InteropServices; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs index 9787a24066..845078ce9d 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs index aaafb59294..66302a524b 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs b/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs index 9c2a0e846e..4dbbeda4fd 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs b/src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs index 4d633452ac..9e49128e11 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs index 06df695c90..fc916d7837 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs @@ -1,19 +1,5 @@ -// Copyright (c) .NET Foundation. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.InteropServices; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs index 0fd9a632b7..38dc533ad2 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics.CodeAnalysis; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs b/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs index 23a5452122..5316efdf75 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs +++ b/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; diff --git a/src/Microsoft.Net.Http.Server/NullLogger.cs b/src/Microsoft.Net.Http.Server/NullLogger.cs index 8e82046da2..a66df859b6 100644 --- a/src/Microsoft.Net.Http.Server/NullLogger.cs +++ b/src/Microsoft.Net.Http.Server/NullLogger.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.Extensions.Logging; diff --git a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs index a897da7d0e..8790de29ab 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + #if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading diff --git a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs index b45b7a2c8f..bc1ed90211 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + #if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading diff --git a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs index 0ad6b902bf..92530f048f 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + #if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs index 0c2453c0f2..bea558e342 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + #if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; using System.Runtime.InteropServices; diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs index 55e5458f04..1ec336af68 100644 --- a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs +++ b/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + #if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. using System; namespace System.Threading diff --git a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs index 79eeb571ef..76feceeff0 100644 --- a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Reflection; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs index f2b4e78568..9c7a60ef9a 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs index f3c60389bb..f80701af0a 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs index 2decf287e0..efac9db46f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs index 39f658eb7d..0fffaf499d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Text; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs index 8f82c75178..ace6b41c00 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs index 0da9062d6e..cbb15b992f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs index a31b24985d..f80d12c9b2 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs index 3a84ed8f22..ae545eec9d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs index 3c3572a104..90274e07bf 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs index 6de4a8b38d..cbcf912b13 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs index 4b6b17d637..13e62eb367 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs index c244a44753..f0a8a26e2b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Globalization; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs index 0f533cd730..7753f79074 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs index 2b3f1dcafb..ece5ef4b39 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs @@ -1,38 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- -// Copyright 2011-2012 Katana contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs index 9ad00ca84d..4f3ab879ca 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs index 150ccea190..c04376d4ee 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics.CodeAnalysis; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs index 6597bbaf36..5129e4e4bb 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Text; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index 628d910c5e..a16d11fd71 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs index 4db16705ed..7a3625efd6 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs index 451a327025..e710e05660 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics.CodeAnalysis; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs index a974c723e5..792822d3b5 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.Net.Http.Server { diff --git a/src/Microsoft.Net.Http.Server/Resources.Designer.cs b/src/Microsoft.Net.Http.Server/Resources.Designer.cs index cee3ec2600..8a3ccb7f45 100644 --- a/src/Microsoft.Net.Http.Server/Resources.Designer.cs +++ b/src/Microsoft.Net.Http.Server/Resources.Designer.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. //------------------------------------------------------------------------------ // diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.Net.Http.Server/TimeoutManager.cs index 9762c254a7..2daae9ff86 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.Net.Http.Server/TimeoutManager.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.InteropServices; diff --git a/src/Microsoft.Net.Http.Server/UrlPrefix.cs b/src/Microsoft.Net.Http.Server/UrlPrefix.cs index 4c23f598d5..d63de7c648 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefix.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefix.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Globalization; diff --git a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs index bfef83e0d2..3c820b73f8 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs +++ b/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections; diff --git a/src/Microsoft.Net.Http.Server/ValidationHelper.cs b/src/Microsoft.Net.Http.Server/ValidationHelper.cs index fc84aa1ecd..0174663b24 100644 --- a/src/Microsoft.Net.Http.Server/ValidationHelper.cs +++ b/src/Microsoft.Net.Http.Server/ValidationHelper.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ----------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Globalization; diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs index 2e2f0cb1f8..903103d60e 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.Net.Http.Server/WebListener.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Http.Server/WebListenerException.cs b/src/Microsoft.Net.Http.Server/WebListenerException.cs index 3c0cb7bb89..3b3b91d8ac 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerException.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerException.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.ComponentModel; diff --git a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs index a952137227..20a8d4e279 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs +++ b/src/Microsoft.Net.Http.Server/WebListenerSettings.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.Extensions.Logging; diff --git a/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs b/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs index 8ee6466a00..4338d88f54 100644 --- a/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs +++ b/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs index 5b29a3bc4c..a7af472718 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ==++== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ==--== +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #if NETSTANDARD1_3 diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs index aef2c8b323..3bf6498c75 100644 --- a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -// ==++== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ==--== +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #if NETSTANDARD1_3 diff --git a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs index 9bb3fa57fe..09b226a964 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs @@ -1,4 +1,7 @@ -using System.Threading.Tasks; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; namespace System.Net.WebSockets { diff --git a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs index 8753b1c60e..c7e3a8da7a 100644 --- a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs +++ b/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs index e96eb7040f..4fda684f19 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Linq; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs index 4ef9a8d2e0..d6766522f6 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Threading.Tasks; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs index bffcf16ceb..3ea7b496ba 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.IO; using System.Net.Http; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs index a311b6b770..c3db238383 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 62bd825730..ba4ea1d02d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index 3ff2c613f6..ddcf183170 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Net.Http; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index ce7db01208..e9a4714c1d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index 9df0c89089..f7eee58eeb 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index 6c63806476..b8d841bb92 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Linq; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 9d31c385b5..b5f7ba1a0f 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index 62616c6a6e..ce22eb6074 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs index 002003ac36..ba02e65bb0 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs index 6acf44068d..2278c18bbe 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs index 02a933d838..fb6ccbee89 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Hosting.Server; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs index 69b28cd960..df28ef5258 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -1,19 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Net.Http; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 8009331223..54b9c6e72e 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Net; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index ad25c21142..85ed02b553 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.IO; using System.Net.Http; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index 274ab452e0..987352df62 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index 51229b93bb..7f2c2a4725 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index c3b1c90caa..97fe7a1b81 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Net.Http; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index aa2d76fd29..058e8f2fcd 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 27ad36cabf..0c3efc5835 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index b3a3b1da74..cd5f58ca20 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index 0374617f2f..af6a828df2 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index a34729f912..d6fe87fb74 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs index 12b379c22c..fe6fc0c827 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Net; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 21e60cb3aa..65d7691dd3 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs index 3ba29a660a..0d5066f752 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index 7fb09686ee..dbfcaa2e05 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Net.Http; From e1ef220bf1dc8e43c53ace9d2663483240b8eae3 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 30 Sep 2016 11:41:11 -0700 Subject: [PATCH 414/597] Add Contributing, Readme, and update License file. --- CONTRIBUTING.md | 4 ++++ LICENSE.txt | 2 +- README.md | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 CONTRIBUTING.md create mode 100644 README.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..64ff041d5c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +Contributing +====== + +Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. diff --git a/LICENSE.txt b/LICENSE.txt index d85a1524ad..0bdc1962b6 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +Copyright (c) .NET Foundation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use these files except in compliance with the License. You may obtain a copy of the diff --git a/README.md b/README.md new file mode 100644 index 0000000000..d30e60e456 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +WebListener +================= + +This repo contains a web server for ASP.NET Core based on the Windows [Http Server API](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364510.aspx). + +This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo. From 3fa95d1ff89ca97f8848e5c1742a7413a87777d1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 28 Sep 2016 11:52:58 -0700 Subject: [PATCH 415/597] Updating partner package versions --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- .../project.json | 9 ++++--- src/Microsoft.Net.Http.Server/project.json | 25 ++++++------------- .../project.json | 8 +++--- .../project.json | 10 +++----- .../project.json | 6 ++--- 8 files changed, 25 insertions(+), 39 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 949af79c8c..5b4f1f1c41 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -13,7 +13,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 8f3fda7f58..482185e79e 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index f0c79263dd..94fb1c19b9 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index cf4cefd3f1..a61e1ebbdc 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -9,12 +9,13 @@ }, "dependencies": { "Microsoft.AspNetCore.Hosting": "1.1.0-*", - "Microsoft.Net.Http.Headers": "1.1.0-*", - "Microsoft.Net.Http.Server": "1.1.0-*", "Microsoft.Extensions.TaskCache.Sources": { "version": "1.1.0-*", "type": "build" - } + }, + "Microsoft.Net.Http.Headers": "1.1.0-*", + "Microsoft.Net.Http.Server": "1.1.0-*", + "NETStandard.Library": "1.6.1-*" }, "buildOptions": { "allowUnsafe": true, @@ -29,7 +30,7 @@ "net451": {}, "netstandard1.3": { "dependencies": { - "System.Security.Claims": "4.0.1-*" + "System.Security.Claims": "4.3.0-*" } } } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index b21926e4d5..4a8052c6b3 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -9,7 +9,8 @@ }, "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Primitives": "1.1.0-*" + "Microsoft.Extensions.Primitives": "1.1.0-*", + "NETStandard.Library": "1.6.1-*" }, "buildOptions": { "allowUnsafe": true, @@ -34,23 +35,11 @@ "type": "build", "version": "1.1.0-*" }, - "Microsoft.Win32.Primitives": "4.0.1-*", - "System.Diagnostics.Contracts": "4.0.1-*", - "System.Diagnostics.Debug": "4.0.11-*", - "System.Diagnostics.Tools": "4.0.1-*", - "System.IO": "4.1.0-*", - "System.IO.FileSystem": "4.0.1-*", - "System.Net.Primitives": "4.0.11-*", - "System.Net.WebSockets": "4.0.0-*", - "System.Runtime.Extensions": "4.1.0-*", - "System.Runtime.InteropServices": "4.1.0-*", - "System.Security.Claims": "4.0.1-*", - "System.Security.Cryptography.X509Certificates": "4.1.0-*", - "System.Security.Principal.Windows": "4.0.0-*", - "System.Text.Encoding.Extensions": "4.0.11-*", - "System.Threading": "4.0.11-*", - "System.Threading.Overlapped": "4.0.1-*", - "System.Threading.Timer": "4.0.1" + "System.Diagnostics.Contracts": "4.3.0-*", + "System.Net.WebSockets": "4.3.0-*", + "System.Security.Claims": "4.3.0-*", + "System.Security.Principal.Windows": "4.3.0-*", + "System.Threading.Overlapped": "4.3.0-*" } } } diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index fd7ec4854b..392aaf28ea 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -14,13 +14,11 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" }, - "System.Net.Http.WinHttpHandler": "4.0.0-*", - "System.Net.Requests": "4.0.11-*", - "System.Net.WebHeaderCollection": "4.0.1-*", - "System.Net.WebSockets.Client": "4.0.0" + "System.Net.Http.WinHttpHandler": "4.3.0-*", + "System.Net.WebSockets.Client": "4.3.0-*" } }, "net451": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index c183b6d9b9..52a6813630 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -2,21 +2,19 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "1.1.0-*", "Microsoft.AspNetCore.Testing": "1.1.0-*", + "Microsoft.Net.Http.Server": "1.1.0-*", "xunit": "2.2.0-*" }, "frameworks": { "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" }, - "System.Net.Http": "4.1.0-*", - "System.Net.Http.WinHttpHandler": "4.0.0-*", - "System.Net.Requests": "4.0.11-*", - "System.Net.WebSockets.Client": "4.0.0-*" + "System.Net.Http.WinHttpHandler": "4.3.0-*", + "System.Net.WebSockets.Client": "4.3.0-*" } }, "net451": { diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index 4c7be985ef..9529d628fd 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -1,4 +1,4 @@ -{ +{ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", @@ -9,11 +9,11 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0-*", + "version": "1.1.0-*", "type": "platform" } } }, - "net451": { } + "net451": {} } } \ No newline at end of file From 2433448bc7410fc44bc513c911159ffd9ca6f49f Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 5 Oct 2016 10:19:20 -0700 Subject: [PATCH 416/597] #259 Auto-chunk even for Connection: close responses --- src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs | 4 ++-- .../ResponseHeaderTests.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs index a16d11fd71..7185d039ff 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs @@ -453,14 +453,14 @@ namespace Microsoft.Net.Http.Server _boundaryType = BoundaryType.ContentLength; _expectedBodyLength = 0; } - else if (keepConnectionAlive && requestVersion == Constants.V1_1) + else if (requestVersion == Constants.V1_1) { _boundaryType = BoundaryType.Chunked; Headers[HttpKnownHeaderNames.TransferEncoding] = Constants.Chunked; } else { - // The length cannot be determined, so we must close the connection + // v1.0 and the length cannot be determined, so we must close the connection after writing data keepConnectionAlive = false; _boundaryType = BoundaryType.Close; } diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index b5f7ba1a0f..8183b52aed 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -133,7 +133,8 @@ namespace Microsoft.AspNetCore.Server.WebListener response.EnsureSuccessStatusCode(); Assert.True(response.Headers.ConnectionClose.Value); Assert.Equal(new string[] { "close" }, response.Headers.GetValues("Connection")); - Assert.False(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.TransferEncodingChunked.HasValue); + Assert.True(response.Headers.TransferEncodingChunked); IEnumerable values; var result = response.Content.Headers.TryGetValues("Content-Length", out values); Assert.False(result); From 47fc36453b35396bcde43ed573c30b21b51116b0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 5 Oct 2016 15:32:19 -0700 Subject: [PATCH 417/597] Update the samples and launchsettings (#264) --- samples/HelloWorld/Properties/launchSettings.json | 4 ++-- .../HotAddSample/Properties/launchSettings.json | 10 +++++++--- samples/HotAddSample/Startup.cs | 14 +++++++++++++- .../SelfHostServer/Properties/launchSettings.json | 10 +++++++--- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/samples/HelloWorld/Properties/launchSettings.json b/samples/HelloWorld/Properties/launchSettings.json index 6161971048..f96a6f4415 100644 --- a/samples/HelloWorld/Properties/launchSettings.json +++ b/samples/HelloWorld/Properties/launchSettings.json @@ -1,7 +1,7 @@ { "profiles": { - "sample": { - "commandName": "sample", + "HelloWorld": { + "commandName": "Project", "launchBrowser": true, "launchUrl": "http://localhost:8080" } diff --git a/samples/HotAddSample/Properties/launchSettings.json b/samples/HotAddSample/Properties/launchSettings.json index 62f539fadd..5df19c1327 100644 --- a/samples/HotAddSample/Properties/launchSettings.json +++ b/samples/HotAddSample/Properties/launchSettings.json @@ -1,9 +1,13 @@ { "profiles": { - "web": { - "commandName": "web", + "HotAddSample": { + "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:12345" + "launchUrl": "http://localhost:12345", + "environmentVariables": { + "ASPNETCORE_URLS": "http://localhost:12345", + "ASPNETCORE_ENVIRONMENT": "Development" + } } } } \ No newline at end of file diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index 089b14d01d..a6cf016890 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -2,6 +2,8 @@ using System; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Server.WebListener; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Server; @@ -12,11 +14,21 @@ namespace HotAddSample // will be reset before the end of the request. public class Startup { + public void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + ListenerSettings = options.ListenerSettings; + }); + } + + public WebListenerSettings ListenerSettings { get; set; } + public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { loggerfactory.AddConsole(LogLevel.Information); - var addresses = app.ServerFeatures.Get().Settings.UrlPrefixes; + var addresses = ListenerSettings.UrlPrefixes; addresses.Add("http://localhost:12346/pathBase/"); app.Use(async (context, next) => diff --git a/samples/SelfHostServer/Properties/launchSettings.json b/samples/SelfHostServer/Properties/launchSettings.json index bca9b1f442..f2eaeff38b 100644 --- a/samples/SelfHostServer/Properties/launchSettings.json +++ b/samples/SelfHostServer/Properties/launchSettings.json @@ -1,9 +1,13 @@ { "profiles": { - "web": { - "commandName": "web", + "SelfHostServer": { + "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:8080" + "launchUrl": "http://localhost:8080/", + "environmentVariables": { + "ASPNETCORE_URLS": "http://localhost:8080/", + "ASPNETCORE_ENVIRONMENT": "Development" + } } } } \ No newline at end of file From 0f69d6351d2a270d68a30080a722110cb48c08fd Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 7 Oct 2016 15:35:09 -0700 Subject: [PATCH 418/597] #214 Use ConditionalFacts to skip tests on Mac and Linux at the assembly levely --- .../AuthenticationTests.cs | 24 +++---- .../HttpsTests.cs | 11 ++-- .../Properties/AssemblyInfo.cs | 7 ++ .../RequestBodyTests.cs | 15 +++-- .../RequestHeaderTests.cs | 5 +- .../RequestTests.cs | 13 ++-- .../ResponseBodyTests.cs | 23 +++---- .../ResponseCachingTests.cs | 21 +++--- .../ResponseHeaderTests.cs | 19 +++--- .../ResponseSendFileTests.cs | 29 +++++---- .../ResponseTests.cs | 19 +++--- .../ServerTests.cs | 21 +++--- .../WebSocketTests.cs | 6 +- .../AuthenticationTests.cs | 6 +- .../HttpsTests.cs | 11 ++-- .../Properties/AssemblyInfo.cs | 7 ++ .../RequestBodyTests.cs | 27 ++++---- .../RequestHeaderTests.cs | 7 +- .../RequestTests.cs | 19 +++--- .../ResponseBodyTests.cs | 47 +++++++------- .../ResponseCachingTests.cs | 64 +++++++++---------- .../ResponseHeaderTests.cs | 35 +++++----- .../ResponseSendFileTests.cs | 47 +++++++------- .../ResponseTests.cs | 13 ++-- .../ServerTests.cs | 22 +++---- .../WebSocketTests.cs | 4 +- 26 files changed, 274 insertions(+), 248 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs create mode 100644 test/Microsoft.Net.Http.Server.FunctionalTests/Properties/AssemblyInfo.cs diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs index 4fda684f19..b9dedca1bb 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.WebListener private static bool AllowAnoymous = true; private static bool DenyAnoymous = false; - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.None)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.None)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] @@ -204,7 +204,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task AuthTypes_GetMultipleDescriptions() { string address; @@ -226,7 +226,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -254,7 +254,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -364,7 +364,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -389,7 +389,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -412,7 +412,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented @@ -435,7 +435,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented @@ -458,7 +458,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs index 3ea7b496ba..2309b9cf7d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener @@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { private const string Address = "https://localhost:9090/"; - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_200OK_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -29,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_SendHelloWorld_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -44,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_EchoHelloWorld_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -62,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { using (Utilities.CreateHttpsServer(async httpContext => @@ -79,7 +80,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertRequested_ClientCertPresent() { using (Utilities.CreateHttpsServer(async httpContext => diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..6d9ec40e96 --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Testing.xunit; + +[assembly: OSSkipCondition(OperatingSystems.MacOSX)] +[assembly: OSSkipCondition(OperatingSystems.Linux)] \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index ba4ea1d02d..6214e65d72 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -9,13 +9,14 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener { public class RequestBodyTests { - [Fact] + [ConditionalFact] public async Task RequestBody_ReadSync_Success() { string address; @@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAync_Success() { string address; @@ -50,7 +51,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } #if !NETCOREAPP1_0 - [Fact] + [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { string address; @@ -69,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } #endif - [Fact] + [ConditionalFact] public async Task RequestBody_InvalidBuffer_ArgumentException() { string address; @@ -91,7 +92,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadSyncPartialBody_Success() { StaggardContent content = new StaggardContent(); @@ -112,7 +113,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAsyncPartialBody_Success() { StaggardContent content = new StaggardContent(); @@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task RequestBody_PostWithImidateBody_Success() { string address; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs index ddcf183170..196de8dad6 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Primitives; using Xunit; @@ -13,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { public class RequestHeaderTests { - [Fact] + [ConditionalFact] public async Task RequestHeaders_ClientSendsDefaultHeaders_Success() { string address; @@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task RequestHeaders_ClientSendsCustomHeaders_Success() { string address; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs index e9a4714c1d..4e75ac0e0a 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Server; @@ -20,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { public class RequestTests { - [Fact] + [ConditionalFact] public async Task Request_SimpleGet_ExpectedFieldsSet() { string root; @@ -68,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Request_FieldsCanBeSet_Set() { string root; @@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Request_FieldsCanBeSetToNull_Set() { string root; @@ -195,7 +196,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] [InlineData("/", "/", "", "/")] [InlineData("/basepath/", "/basepath", "/basepath", "")] [InlineData("/basepath/", "/basepath/", "/basepath", "/")] @@ -238,7 +239,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Request_DoubleEscapingAllowed() { string root; @@ -256,7 +257,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Theory] + [ConditionalTheory] // The test server defines these prefixes: "/", "/11", "/2/3", "/2", "/11/2" [InlineData("/", "", "/")] [InlineData("/random", "", "/random")] diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs index f7eee58eeb..6842146dd1 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs @@ -9,13 +9,14 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener { public class ResponseBodyTests { - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteNoHeaders_SetsChunked() { string address; @@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteNoHeadersAndFlush_DefaultsToChunked() { string address; @@ -56,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteChunked_ManuallyChunked() { string address; @@ -78,7 +79,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLength_PassedThrough() { string address; @@ -106,7 +107,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthNoneWritten_Throws() { string address; @@ -120,7 +121,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public void ResponseBody_WriteContentLengthNotEnoughWritten_Throws() { string address; @@ -135,7 +136,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { var completed = false; @@ -154,7 +155,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthExtraWritten_Throws() { var waitHandle = new ManualResetEvent(false); @@ -193,7 +194,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseBody_Write_TriggersOnStarting() { var onStartingCalled = false; @@ -221,7 +222,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } #if NET451 - [Fact] + [ConditionalFact] public async Task ResponseBody_BeginWrite_TriggersOnStarting() { var onStartingCalled = false; @@ -249,7 +250,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } #endif - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteAsync_TriggersOnStarting() { var onStartingCalled = false; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index b8d841bb92..0f0c702d25 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -5,13 +5,14 @@ using System; using System.Linq; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests { public class ResponseCachingTests { - [Fact] + [ConditionalFact] public async Task Caching_NoCacheControl_NotCached() { var requestCount = 1; @@ -29,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [ConditionalFact] public async Task Caching_JustPublic_NotCached() { var requestCount = 1; @@ -48,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [ConditionalFact] public async Task Caching_MaxAge_Cached() { var requestCount = 1; @@ -67,7 +68,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [ConditionalFact] public async Task Caching_SMaxAge_Cached() { var requestCount = 1; @@ -86,7 +87,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [ConditionalFact] public async Task Caching_SMaxAgeAndMaxAge_SMaxAgePreferredCached() { var requestCount = 1; @@ -105,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [ConditionalFact] public async Task Caching_Expires_Cached() { var requestCount = 1; @@ -125,7 +126,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Theory] + [ConditionalTheory] [InlineData("Set-cookie")] [InlineData("vary")] [InlineData("pragma")] @@ -148,7 +149,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Theory] + [ConditionalTheory] [InlineData("0")] [InlineData("-1")] public async Task Caching_InvalidExpires_NotCached(string expiresValue) @@ -170,7 +171,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [ConditionalFact] public async Task Caching_ExpiresWithoutPublic_NotCached() { var requestCount = 1; @@ -189,7 +190,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact] + [ConditionalFact] public async Task Caching_MaxAgeAndExpires_MaxAgePreferred() { var requestCount = 1; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 8183b52aed..d5fc13c3a6 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -9,6 +9,7 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Primitives; using Xunit; @@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { public class ResponseHeaderTests { - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsDefaultHeaders_Success() { string address; @@ -36,7 +37,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsSingleValueKnownHeaders_Success() { string address; @@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsMultiValueKnownHeaders_Success() { string address; @@ -88,7 +89,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() { string address; @@ -116,7 +117,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsConnectionClose_Closed() { string address; @@ -141,7 +142,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_HTTP10Request_Gets11Close() { string address; @@ -164,7 +165,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_HTTP10RequestWithChunkedHeader_ManualChunking() { string address; @@ -193,7 +194,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Headers_FlushSendsHeaders_Success() { string address; @@ -224,7 +225,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Headers_FlushAsyncSendsHeaders_Success() { string address; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs index ce22eb6074..4ee3342188 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs @@ -11,6 +11,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener @@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.WebListener FileLength = new FileInfo(AbsoluteFilePath).Length; } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_SupportKeys_Present() { string address; @@ -69,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_MissingFile_Throws() { var waitHandle = new ManualResetEvent(false); @@ -103,7 +104,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() { string address; @@ -122,7 +123,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_RelativeFile_Success() { string address; @@ -141,7 +142,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_Unspecified_Chunked() { string address; @@ -160,7 +161,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_MultipleWrites_Chunked() { string address; @@ -180,7 +181,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_HalfOfFile_Chunked() { string address; @@ -199,7 +200,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_OffsetOutOfRange_Throws() { var completed = false; @@ -218,7 +219,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_CountOutOfRange_Throws() { var completed = false; @@ -237,7 +238,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_Count0_Chunked() { string address; @@ -256,7 +257,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_ContentLength_PassedThrough() { string address; @@ -277,7 +278,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_ContentLengthSpecific_PassedThrough() { string address; @@ -298,7 +299,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_ContentLength0_PassedThrough() { string address; @@ -319,7 +320,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_TriggersOnStarting() { var onStartingCalled = false; diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs index ba02e65bb0..950e80aca3 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs @@ -8,13 +8,14 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.AspNetCore.Server.WebListener { public class ResponseTests { - [Fact] + [ConditionalFact] public async Task Response_ServerSendsDefaultResponse_ServerProvidesStatusCodeAndReasonPhrase() { string address; @@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Response_ServerSendsSpecificStatus_ServerProvidesReasonPhrase() { string address; @@ -52,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Response_ServerSendsSpecificStatusAndReasonPhrase_PassedThrough() { string address; @@ -72,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Response_ServerSendsCustomStatus_NoReasonPhrase() { string address; @@ -89,7 +90,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Response_StatusCode100_Throws() { string address; @@ -104,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Response_StatusCode0_Throws() { string address; @@ -119,7 +120,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Response_Empty_CallsOnStartingAndOnCompleted() { var onStartingCalled = new ManualResetEvent(false); @@ -150,7 +151,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Response_OnStartingThrows_StillCallsOnCompleted() { var onStartingCalled = new ManualResetEvent(false); @@ -180,7 +181,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Response_OnStartingThrowsAfterWrite_WriteThrowsAndStillCallsOnCompleted() { var onStartingCalled = new ManualResetEvent(false); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs index 2278c18bbe..d84295a7b3 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Server; @@ -21,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { public class ServerTests { - [Fact] + [ConditionalFact] public async Task Server_200OK_Success() { string address; @@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Server_SendHelloWorld_Success() { string address; @@ -50,7 +51,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Server_EchoHelloWorld_Success() { string address; @@ -67,7 +68,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Server_ShutdownDurringRequest_Success() { Task responseTask; @@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal("Hello World", response); } - [Fact] + [ConditionalFact] public void Server_AppException_ClientReset() { string address; @@ -105,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public void Server_MultipleOutstandingSyncRequests_Success() { int requestLimit = 10; @@ -138,7 +139,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public void Server_MultipleOutstandingAsyncRequests_Success() { int requestLimit = 10; @@ -168,7 +169,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Server_ClientDisconnects_CallCanceled() { TimeSpan interval = TimeSpan.FromSeconds(1); @@ -204,7 +205,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Server_Abort_CallCanceled() { TimeSpan interval = TimeSpan.FromSeconds(100); @@ -234,7 +235,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [Fact] + [ConditionalFact] public async Task Server_SetQueueLimit_Success() { // This is just to get a dynamic port diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs index df28ef5258..5d3c28c736 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs @@ -13,10 +13,10 @@ using Xunit; namespace Microsoft.AspNetCore.Server.WebListener { + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public class WebSocketTests { [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketTests_SupportKeys_Present() { string address; @@ -43,7 +43,6 @@ namespace Microsoft.AspNetCore.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketTests_AfterHeadersSent_Throws() { bool? upgradeThrew = null; @@ -71,7 +70,6 @@ namespace Microsoft.AspNetCore.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_Success() { ManualResetEvent waitHandle = new ManualResetEvent(false); @@ -97,7 +95,6 @@ namespace Microsoft.AspNetCore.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_WithOnStarting_CallbackCalled() { var callbackCalled = false; @@ -130,7 +127,6 @@ namespace Microsoft.AspNetCore.Server.WebListener } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_SendAndReceive_Success() { byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 54b9c6e72e..93b21417e8 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.Net.Http.Server private static bool AllowAnoymous = true; private static bool DenyAnoymous = false; - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.None)] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] @@ -114,7 +114,7 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -145,7 +145,7 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index 85ed02b553..58bf36998c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server @@ -15,7 +16,7 @@ namespace Microsoft.Net.Http.Server // Note these tests can't use dynamic ports or run concurrently because the ssl cert must be pre-registered with a specific port. private const string Address = "https://localhost:9090/"; - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_200OK_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -30,7 +31,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_SendHelloWorld_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -48,7 +49,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_EchoHelloWorld_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -69,7 +70,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { using (var server = Utilities.CreateHttpsServer()) @@ -86,7 +87,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertRequested_ClientCertPresent() { using (var server = Utilities.CreateHttpsServer()) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..6d9ec40e96 --- /dev/null +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Testing.xunit; + +[assembly: OSSkipCondition(OperatingSystems.MacOSX)] +[assembly: OSSkipCondition(OperatingSystems.Linux)] \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index 7f2c2a4725..87b6d62dbf 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -9,13 +9,14 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server { public class RequestBodyTests { - [Fact] + [ConditionalFact] public async Task RequestBody_ReadSync_Success() { string address; @@ -34,7 +35,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAync_Success() { string address; @@ -53,7 +54,7 @@ namespace Microsoft.Net.Http.Server } } #if NET451 - [Fact] + [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { string address; @@ -73,7 +74,7 @@ namespace Microsoft.Net.Http.Server } #endif - [Fact] + [ConditionalFact] public async Task RequestBody_InvalidBuffer_ArgumentException() { string address; @@ -97,7 +98,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadSyncPartialBody_Success() { StaggardContent content = new StaggardContent(); @@ -120,7 +121,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAsyncPartialBody_Success() { StaggardContent content = new StaggardContent(); @@ -143,7 +144,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_PostWithImidateBody_Success() { string address; @@ -169,7 +170,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAsyncAlreadyCanceled_ReturnsCanceledTask() { string address; @@ -193,7 +194,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAsyncPartialBodyWithCancellationToken_Success() { StaggardContent content = new StaggardContent(); @@ -217,7 +218,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAsyncPartialBodyWithTimeout_Success() { StaggardContent content = new StaggardContent(); @@ -242,7 +243,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAsyncPartialBodyAndCancel_Canceled() { StaggardContent content = new StaggardContent(); @@ -267,7 +268,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAsyncPartialBodyAndExpiredTimeout_Canceled() { StaggardContent content = new StaggardContent(); @@ -294,7 +295,7 @@ namespace Microsoft.Net.Http.Server // Make sure that using our own disconnect token as a read cancellation token doesn't // cause recursion problems when it fires and calls Abort. - [Fact] + [ConditionalFact] public async Task RequestBody_ReadAsyncPartialBodyAndDisconnectedClient_Canceled() { StaggardContent content = new StaggardContent(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index 97fe7a1b81..2511e80d28 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Primitives; using Xunit; @@ -13,7 +14,7 @@ namespace Microsoft.Net.Http.Server { public class RequestHeaderTests { - [Fact] + [ConditionalFact] public async Task RequestHeaders_ClientSendsDefaultHeaders_Success() { string address; @@ -38,7 +39,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestHeaders_ClientSendsCustomHeaders_Success() { string address; @@ -65,7 +66,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task RequestHeaders_ClientSendsUtf8Headers_Success() { string address; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index 058e8f2fcd..f86e9a1124 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -7,13 +7,14 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server { public class RequestTests { - [Fact] + [ConditionalFact] public async Task Request_SimpleGet_Success() { string root; @@ -50,7 +51,7 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] [InlineData("/", "/", "", "/")] [InlineData("/basepath/", "/basepath", "/basepath", "")] [InlineData("/basepath/", "/basepath/", "/basepath", "/")] @@ -82,7 +83,7 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] [InlineData("/path%")] [InlineData("/path%XY")] [InlineData("/path%F")] @@ -100,7 +101,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Request_DoubleEscapingAllowed() { string root; @@ -112,7 +113,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Request_OptionsStar_EmptyPath() { string root; @@ -127,7 +128,7 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] // The test server defines these prefixes: "/", "/11", "/2/3", "/2", "/11/2" [InlineData("/", "", "/")] [InlineData("/random", "", "/random")] @@ -171,7 +172,7 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] [InlineData("%D0%A4", "Ф")] [InlineData("%d0%a4", "Ф")] [InlineData("%E0%A4%AD", "भ")] @@ -212,7 +213,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(expect, actualPath.TrimStart('/')); } - [Theory] + [ConditionalTheory] [InlineData("/%%32")] [InlineData("/%%20")] [InlineData("/%F0%8F%8F%BF")] @@ -233,7 +234,7 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] // Overlong ASCII [InlineData("/%C0%A4", "/%C0%A4")] [InlineData("/%C1%BF", "/%C1%BF")] diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 0c3efc5835..3f72bc88f6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -9,13 +9,14 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server { public class ResponseBodyTests { - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() { string address; @@ -38,7 +39,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_FlushThenWrite_DefaultsToChunkedAndTerminates() { string address; @@ -61,7 +62,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteChunked_ManuallyChunked() { string address; @@ -86,7 +87,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLength_PassedThrough() { string address; @@ -117,7 +118,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthNoneWritten_Aborts() { string address; @@ -138,7 +139,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Aborts() { string address; @@ -155,7 +156,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { string address; @@ -173,7 +174,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthExtraWritten_Throws() { string address; @@ -198,7 +199,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteZeroCount_StartsChunkedResponse() { string address; @@ -222,7 +223,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteAsyncWithActiveCancellationToken_Success() { string address; @@ -243,7 +244,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_WriteAsyncWithTimerCancellationToken_Success() { string address; @@ -265,7 +266,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_FirstWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -295,7 +296,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_FirstWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -324,7 +325,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_SecondWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -346,7 +347,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_SecondWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -367,7 +368,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeFirstWrite_WriteThrows() { string address; @@ -397,7 +398,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeFirstWriteAsync_WriteThrows() { string address; @@ -429,7 +430,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_ClientDisconnectsBeforeFirstWrite_WriteCompletesSilently() { string address; @@ -452,7 +453,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_ClientDisconnectsBeforeFirstWriteAsync_WriteCompletesSilently() { string address; @@ -475,7 +476,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWrite_WriteThrows() { string address; @@ -509,7 +510,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWriteAsync_WriteThrows() { string address; @@ -543,7 +544,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_ClientDisconnectsBeforeSecondWrite_WriteCompletesSilently() { string address; @@ -573,7 +574,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseBody_ClientDisconnectsBeforeSecondWriteAsync_WriteCompletesSilently() { string address; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index cd5f58ca20..ce797fc9a0 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.Net.Http.Server _fileLength = new FileInfo(_absoluteFilePath).Length; } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlWithoutContentType_NotCached() { string address; @@ -57,7 +57,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlWithContentType_Cached() { string address; @@ -84,7 +84,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] // Http.Sys does not set the optional Age header for cached content. // http://tools.ietf.org/html/rfc7234#section-5.1 public async Task Caching_CheckAge_NotSentWithCachedContent() @@ -115,7 +115,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] // Http.Sys does not update the optional Age header for cached content. // http://tools.ietf.org/html/rfc7234#section-5.1 public async Task Caching_SetAge_AgeHeaderCachedAndNotUpdated() @@ -149,7 +149,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlZeroSeconds_NotCached() { string address; @@ -183,7 +183,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlMiliseconds_NotCached() { string address; @@ -217,7 +217,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlNegative_NotCached() { string address; @@ -251,7 +251,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlHuge_Cached() { string address; @@ -278,7 +278,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlAndWriteBody_Cached() { string address; @@ -309,7 +309,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlAndWriteAsyncBody_Cached() { string address; @@ -340,7 +340,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_Flush_NotCached() { string address; @@ -373,7 +373,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_WriteFlush_NotCached() { string address; @@ -407,7 +407,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_WriteFullContentLength_Cached() { string address; @@ -438,7 +438,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SendFileNoContentLength_NotCached() { string address; @@ -471,7 +471,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SendFileWithFullContentLength_Cached() { string address; @@ -502,7 +502,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_SetTtlAndStatusCode_Cached() { string address; @@ -542,7 +542,7 @@ namespace Microsoft.Net.Http.Server } // Only GET requests can have cached responses. - [Theory] + [ConditionalTheory] // See HTTP_VERB for known verbs [InlineData("HEAD")] [InlineData("UNKNOWN")] @@ -600,7 +600,7 @@ namespace Microsoft.Net.Http.Server // RFC violation. http://tools.ietf.org/html/rfc7234#section-4.4 // "A cache MUST invalidate the effective Request URI ... when a non-error status code // is received in response to an unsafe request method." - [Theory] + [ConditionalTheory] // See HTTP_VERB for known verbs [InlineData("HEAD")] [InlineData("UNKNOWN")] @@ -667,7 +667,7 @@ namespace Microsoft.Net.Http.Server // RFC violation / implementation limiation, Vary is not respected. // http://tools.ietf.org/html/rfc7234#section-4.1 - [Fact] + [ConditionalFact] public async Task Caching_SetVary_NotRespected() { string address; @@ -698,7 +698,7 @@ namespace Microsoft.Net.Http.Server } // http://tools.ietf.org/html/rfc7234#section-3.2 - [Fact] + [ConditionalFact] public async Task Caching_RequestAuthorization_NotCached() { string address; @@ -732,7 +732,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_RequestAuthorization_NotServedFromCache() { string address; @@ -768,7 +768,7 @@ namespace Microsoft.Net.Http.Server // Responses can be cached for requests with Pragma: no-cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact] + [ConditionalFact] public async Task Caching_RequestPragmaNoCache_Cached() { string address; @@ -797,7 +797,7 @@ namespace Microsoft.Net.Http.Server // RFC violation, Requests with Pragma: no-cache should not be served from cache. // http://tools.ietf.org/html/rfc7234#section-5.4 // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact] + [ConditionalFact] public async Task Caching_RequestPragmaNoCache_NotRespectedAndServedFromCache() { string address; @@ -825,7 +825,7 @@ namespace Microsoft.Net.Http.Server // Responses can be cached for requests with cache-control: no-cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact] + [ConditionalFact] public async Task Caching_RequestCacheControlNoCache_Cached() { string address; @@ -853,7 +853,7 @@ namespace Microsoft.Net.Http.Server // RFC violation, Requests with Cache-Control: no-cache should not be served from cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact] + [ConditionalFact] public async Task Caching_RequestCacheControlNoCache_NotRespectedAndServedFromCache() { string address; @@ -881,7 +881,7 @@ namespace Microsoft.Net.Http.Server // RFC violation // http://tools.ietf.org/html/rfc7234#section-5.2.1.1 - [Fact] + [ConditionalFact] public async Task Caching_RequestCacheControlMaxAgeZero_NotRespectedAndServedFromCache() { string address; @@ -909,7 +909,7 @@ namespace Microsoft.Net.Http.Server // RFC violation // http://tools.ietf.org/html/rfc7234#section-5.2.1.3 - [Fact] + [ConditionalFact] public async Task Caching_RequestCacheControlMinFreshOutOfRange_NotRespectedAndServedFromCache() { string address; @@ -936,7 +936,7 @@ namespace Microsoft.Net.Http.Server } // Http.Sys limitation, partial responses are not cached. - [Fact] + [ConditionalFact] public async Task Caching_CacheRange_NotCached() { string address; @@ -980,7 +980,7 @@ namespace Microsoft.Net.Http.Server } // http://tools.ietf.org/html/rfc7233#section-4.1 - [Fact] + [ConditionalFact] public async Task Caching_RequestRangeFromCache_RangeServedFromCache() { string address; @@ -1010,7 +1010,7 @@ namespace Microsoft.Net.Http.Server } // http://tools.ietf.org/html/rfc7233#section-4.1 - [Fact] + [ConditionalFact] public async Task Caching_RequestMultipleRangesFromCache_RangesServedFromCache() { string address; @@ -1038,7 +1038,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_RequestRangeFromCachedFile_ServedFromCache() { string address; @@ -1070,7 +1070,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Caching_RequestMultipleRangesFromCachedFile_ServedFromCache() { string address; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index af6a828df2..e73b801fc1 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Primitives; using Xunit; @@ -15,7 +16,7 @@ namespace Microsoft.Net.Http.Server { public class ResponseHeaderTests { - [Fact] + [ConditionalFact] public async Task ResponseHeaders_11Request_ServerSendsDefaultHeaders() { string address; @@ -37,7 +38,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_10Request_ServerSendsDefaultHeaders() { string address; @@ -60,7 +61,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_11HeadRequest_ServerSendsDefaultHeaders() { string address; @@ -82,7 +83,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_10HeadRequest_ServerSendsDefaultHeaders() { string address; @@ -105,7 +106,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_11HeadRequestWithContentLength_Success() { string address; @@ -128,7 +129,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_11RequestStatusCodeWithoutBody_NoContentLengthOrChunkedOrClose() { string address; @@ -151,7 +152,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_11HeadRequestStatusCodeWithoutBody_NoContentLengthOrChunkedOrClose() { string address; @@ -174,7 +175,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsSingleValueKnownHeaders_Success() { string address; @@ -199,7 +200,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsMultiValueKnownHeaders_Success() { string address; @@ -228,7 +229,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsCustomHeaders_Success() { string address; @@ -257,7 +258,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_ServerSendsConnectionClose_Closed() { string address; @@ -277,7 +278,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_HTTP10Request_Gets11Close() { string address; @@ -296,7 +297,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_HTTP10Request_AllowsManualChunking() { string address; @@ -327,7 +328,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseHeaders_HTTP10KeepAliveRequest_Gets11Close() { string address; @@ -346,7 +347,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Headers_FlushSendsHeaders_Success() { string address; @@ -382,7 +383,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Headers_FlushAsyncSendsHeaders_Success() { string address; @@ -418,7 +419,7 @@ namespace Microsoft.Net.Http.Server } } - [Theory] + [ConditionalTheory] [InlineData("Server", "\r\nData")] [InlineData("Server", "\0Data")] [InlineData("Server", "Data\r")] diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index d6fe87fb74..af06647383 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server @@ -25,7 +26,7 @@ namespace Microsoft.Net.Http.Server FileLength = new FileInfo(AbsoluteFilePath).Length; } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_MissingFile_Throws() { string address; @@ -43,7 +44,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() { string address; @@ -64,7 +65,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_RelativeFile_Success() { string address; @@ -85,7 +86,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_Unspecified_Chunked() { string address; @@ -106,7 +107,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_MultipleWrites_Chunked() { string address; @@ -128,7 +129,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_HalfOfFile_Chunked() { string address; @@ -149,7 +150,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_OffsetOutOfRange_Throws() { string address; @@ -167,7 +168,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_CountOutOfRange_Throws() { string address; @@ -185,7 +186,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_Count0_Chunked() { string address; @@ -206,7 +207,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_EmptyFileCountUnspecified_SetsChunkedAndFlushesHeaders() { var emptyFilePath = Path.Combine(Directory.GetCurrentDirectory(), "zz_" + Guid.NewGuid().ToString() + "EmptyTestFile.txt"); @@ -234,7 +235,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_ContentLength_PassedThrough() { string address; @@ -256,7 +257,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_ContentLengthSpecific_PassedThrough() { string address; @@ -279,7 +280,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_ContentLength0_PassedThrough() { string address; @@ -302,7 +303,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_WithActiveCancellationToken_Success() { string address; @@ -323,7 +324,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_WithTimerCancellationToken_Success() { string address; @@ -345,7 +346,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFileWriteExceptions_FirstCallWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -375,7 +376,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_FirstSendWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -404,7 +405,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFileExceptions_SecondSendWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -426,7 +427,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_SecondSendWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -447,7 +448,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeFirstSend_SendThrows() { string address; @@ -480,7 +481,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_ClientDisconnectsBeforeFirstSend_SendCompletesSilently() { string address; @@ -503,7 +504,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeSecondSend_SendThrows() { string address; @@ -537,7 +538,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task ResponseSendFile_ClientDisconnectsBeforeSecondSend_SendCompletesSilently() { string address; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs index fe6fc0c827..0fab49a9ae 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs @@ -5,13 +5,14 @@ using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; using Xunit; namespace Microsoft.Net.Http.Server { public class ResponseTests { - [Fact] + [ConditionalFact] public async Task Response_ServerSendsDefaultResponse_ServerProvidesStatusCodeAndReasonPhrase() { string address; @@ -31,7 +32,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Response_ServerSendsSpecificStatus_ServerProvidesReasonPhrase() { string address; @@ -52,7 +53,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Response_ServerSendsSpecificStatusAndReasonPhrase_PassedThrough() { string address; @@ -74,7 +75,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Response_ServerSendsCustomStatus_NoReasonPhrase() { string address; @@ -93,7 +94,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Response_100_Throws() { string address; @@ -109,7 +110,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Response_0_Throws() { string address; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 65d7691dd3..05a433a3d2 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.Net.Http.Server { public class ServerTests { - [Fact] + [ConditionalFact] public async Task Server_200OK_Success() { string address; @@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_SendHelloWorld_Success() { string address; @@ -52,7 +52,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_EchoHelloWorld_Success() { string address; @@ -74,7 +74,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_ClientDisconnects_CallCanceled() { var interval = TimeSpan.FromSeconds(1); @@ -105,7 +105,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_TokenRegisteredAfterClientDisconnects_CallCanceled() { var interval = TimeSpan.FromSeconds(1); @@ -136,7 +136,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_TokenRegisteredAfterResponseSent_Success() { var interval = TimeSpan.FromSeconds(1); @@ -167,7 +167,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_Abort_CallCanceled() { var interval = TimeSpan.FromSeconds(1); @@ -195,7 +195,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_ConnectionCloseHeader_CancellationTokenFires() { var interval = TimeSpan.FromSeconds(1); @@ -228,7 +228,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_SetQueueLimit_Success() { string address; @@ -245,7 +245,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_HotAddPrefix_Success() { string address; @@ -276,7 +276,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact] + [ConditionalFact] public async Task Server_HotRemovePrefix_Success() { string address; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index dbfcaa2e05..eadc50f7cf 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -12,10 +12,10 @@ using Xunit; namespace Microsoft.Net.Http.Server { + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public class WebSocketTests { [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_AfterHeadersSent_Throws() { string address; @@ -36,7 +36,6 @@ namespace Microsoft.Net.Http.Server } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_Success() { string address; @@ -54,7 +53,6 @@ namespace Microsoft.Net.Http.Server } [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task WebSocketAccept_SendAndReceive_Success() { string address; From 9acbc6d898c9ae9a4199ce0724fec2ea9af4d5c5 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 7 Oct 2016 15:37:18 -0700 Subject: [PATCH 419/597] Add travis.yml --- .travis.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..60138360be --- /dev/null +++ b/.travis.yml @@ -0,0 +1,34 @@ +language: csharp +sudo: required +dist: trusty +addons: + apt: + packages: + - gettext + - libcurl4-openssl-dev + - libicu-dev + - libssl-dev + - libunwind8 + - zlib1g +mono: + - 4.0.5 +os: + - linux + - osx +osx_image: xcode7.1 +branches: + only: + - master + - release + - dev + - /^(.*\/)?ci-.*$/ +before_install: + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi +script: + - ./build.sh --quiet verify +notifications: + webhooks: + secure: "XshregcmoXywFrrlIk7MLluUV2Pd8Z/VftrviVZjRL5+3akix2QnP15eT2E13yNtyS1yIc3lWfrVrLLf+H5bN9dUSzxIMNoJQ/S18F/AO5VD5ewd6pLC0uYhUcHdTRQuzjLGVPlt2suKpPllV2SsGlAdGatdCfj5zM6eOG31jaA=" + on_success: always + on_failure: always + on_start: always \ No newline at end of file From 5768f9605ef766fd689a224811614e8023f538dc Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 10 Oct 2016 09:49:27 -0700 Subject: [PATCH 420/597] Add AppVeyor and Travis status badges to the readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index d30e60e456..9b1fb2bb26 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ WebListener ================= +| AppVeyor | Travis | +| ---- | ---- +| [![AppVeyor](https://ci.appveyor.com/api/projects/status/413hlt87c3p24on8/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/WebListener/branch/dev) | [![Travis](https://travis-ci.org/aspnet/WebListener.svg?branch=dev)](https://travis-ci.org/aspnet/WebListener) | + This repo contains a web server for ASP.NET Core based on the Windows [Http Server API](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364510.aspx). This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo. From 21fbdcc476355c3e3cf91acd9b4466ab90d978ef Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 12 Oct 2016 13:46:53 -0700 Subject: [PATCH 421/597] Updating to netcoreapp1.1 --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- .../RequestBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 4 ++-- .../project.json | 2 +- .../ResponseBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 4 ++-- test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- test/Microsoft.Net.Http.Server.Tests/project.json | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 5b4f1f1c41..342ec5501e 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -10,7 +10,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 482185e79e..e1cdd57484 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -11,7 +11,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 94fb1c19b9..19e696585d 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -11,7 +11,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 6214e65d72..ebd6b264c6 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal("Hello World", response); } } -#if !NETCOREAPP1_0 +#if !NETCOREAPP1_1 [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index d5fc13c3a6..9b060f2294 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 392aaf28ea..b27565038d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -11,7 +11,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 3f72bc88f6..5177445589 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -129,7 +129,7 @@ namespace Microsoft.Net.Http.Server var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#if !NETCOREAPP1_0 +#if !NETCOREAPP1_1 // HttpClient retries the request because it didn't get a response. context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index e73b801fc1..a485071fd6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -221,7 +221,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -250,7 +250,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 05a433a3d2..cc5899745e 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -186,7 +186,7 @@ namespace Microsoft.Net.Http.Server context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); -#if !NETCOREAPP1_0 +#if !NETCOREAPP1_1 // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.AcceptAsync(); context.Abort(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 52a6813630..66007106c1 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -7,7 +7,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index 9529d628fd..a4fc014661 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -6,7 +6,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From 336ff5cb3d8f4402a6870a6edc7d2acc5793b6a0 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 12 Oct 2016 16:10:02 -0700 Subject: [PATCH 422/597] Revert "Updating to netcoreapp1.1" This reverts commit 21fbdcc476355c3e3cf91acd9b4466ab90d978ef. --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- .../RequestBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 4 ++-- .../project.json | 2 +- .../ResponseBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 4 ++-- test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- test/Microsoft.Net.Http.Server.Tests/project.json | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 342ec5501e..5b4f1f1c41 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -10,7 +10,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index e1cdd57484..482185e79e 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -11,7 +11,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 19e696585d..94fb1c19b9 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -11,7 +11,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index ebd6b264c6..6214e65d72 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal("Hello World", response); } } -#if !NETCOREAPP1_1 +#if !NETCOREAPP1_0 [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index 9b060f2294..d5fc13c3a6 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index b27565038d..392aaf28ea 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -11,7 +11,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 5177445589..3f72bc88f6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -129,7 +129,7 @@ namespace Microsoft.Net.Http.Server var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#if !NETCOREAPP1_1 +#if !NETCOREAPP1_0 // HttpClient retries the request because it didn't get a response. context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index a485071fd6..e73b801fc1 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -221,7 +221,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -250,7 +250,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index cc5899745e..05a433a3d2 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -186,7 +186,7 @@ namespace Microsoft.Net.Http.Server context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); -#if !NETCOREAPP1_1 +#if !NETCOREAPP1_0 // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.AcceptAsync(); context.Abort(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 66007106c1..52a6813630 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -7,7 +7,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index a4fc014661..9529d628fd 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -6,7 +6,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.1": { + "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From 3651f1f46cbf28650b09cf296be42ce8859b3479 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 13 Oct 2016 11:26:30 -0700 Subject: [PATCH 423/597] Updating to netcoreapp1.1 --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- .../RequestBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 4 ++-- .../project.json | 2 +- .../ResponseBodyTests.cs | 2 +- .../ResponseHeaderTests.cs | 4 ++-- test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- test/Microsoft.Net.Http.Server.Tests/project.json | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 5b4f1f1c41..342ec5501e 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -10,7 +10,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 482185e79e..e1cdd57484 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -11,7 +11,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 94fb1c19b9..19e696585d 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -11,7 +11,7 @@ }, "frameworks": { "net451": {}, - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs index 6214e65d72..ebd6b264c6 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal("Hello World", response); } } -#if !NETCOREAPP1_0 +#if !NETCOREAPP1_1 [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs index d5fc13c3a6..9b060f2294 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.WebListener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 392aaf28ea..b27565038d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -11,7 +11,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 3f72bc88f6..5177445589 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -129,7 +129,7 @@ namespace Microsoft.Net.Http.Server var context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#if !NETCOREAPP1_0 +#if !NETCOREAPP1_1 // HttpClient retries the request because it didn't get a response. context = await server.AcceptAsync(); context.Response.Headers["Content-lenGth"] = " 20 "; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index e73b801fc1..a485071fd6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -221,7 +221,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -250,7 +250,7 @@ namespace Microsoft.Net.Http.Server Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #else Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index 05a433a3d2..cc5899745e 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -186,7 +186,7 @@ namespace Microsoft.Net.Http.Server context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); -#if !NETCOREAPP1_0 +#if !NETCOREAPP1_1 // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.AcceptAsync(); context.Abort(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 52a6813630..66007106c1 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -7,7 +7,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index 9529d628fd..a4fc014661 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -6,7 +6,7 @@ "xunit": "2.2.0-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0-*", From 14986c2dab0e6b8d108f89e9fcbda29fb0aab3c7 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 17 Oct 2016 09:49:59 -0700 Subject: [PATCH 424/597] Branching for 1.1.0-preview1 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 826a1f9035..6197c93176 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..787f63ac02 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..355c682856 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 45f29cc207041b27dac9038ee3888f63b41a8ef4 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 24 Oct 2016 13:40:51 -0700 Subject: [PATCH 425/597] Bump version to 1.0.0. --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- src/Microsoft.AspNetCore.Server.WebListener/project.json | 4 ++-- src/Microsoft.Net.Http.Server/project.json | 2 +- .../project.json | 2 +- test/Microsoft.Net.Http.Server.FunctionalTests/project.json | 2 +- test/Microsoft.Net.Http.Server.Tests/project.json | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 0188f94723..f96d62cfbe 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,7 +3,7 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.Net.Http.Server": "1.0.0-rc2-final" + "Microsoft.Net.Http.Server": "1.0.0" }, "commands": { "sample": "HelloWorld" diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 1371305e91..4f100af911 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,7 +1,7 @@ { "version": "1.1.0-*", "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc2-final", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0", "Microsoft.Extensions.Logging.Console": "1.0.0" }, "buildOptions": { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index f33119839b..11c1095a86 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc2-final", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0", "Microsoft.Extensions.Logging.Console": "1.0.0" }, "buildOptions": { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index bdfe64508c..6fd4fa8c9b 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-rc2-final", + "version": "1.0.0", "description": "ASP.NET Core HTTP server for Windows.", "packOptions": { "tags": [ @@ -10,7 +10,7 @@ "dependencies": { "Microsoft.AspNetCore.Hosting": "1.0.0", "Microsoft.Net.Http.Headers": "1.0.0", - "Microsoft.Net.Http.Server": "1.0.0-rc2-final" + "Microsoft.Net.Http.Server": "1.0.0" }, "buildOptions": { "allowUnsafe": true, diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index b0b467ba09..6c59ede1cf 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-rc2-final", + "version": "1.0.0", "description": ".NET HTTP server that uses the Windows HTTP Server API.", "packOptions": { "tags": [ diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 17449f517c..32717e085a 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -6,7 +6,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Server.WebListener": "1.0.0-rc2-final", + "Microsoft.AspNetCore.Server.WebListener": "1.0.0", "Microsoft.AspNetCore.Testing": "1.0.0", "xunit": "2.2.0-*" }, diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index f69d545db9..dbecc2d495 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -2,7 +2,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "1.0.0-rc2-final", + "Microsoft.Net.Http.Server": "1.0.0", "Microsoft.AspNetCore.Testing": "1.0.0", "xunit": "2.2.0-*" }, diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index bfdd758b97..bd58330d2c 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -2,7 +2,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "1.0.0-rc2-final", + "Microsoft.Net.Http.Server": "1.0.0", "xunit": "2.2.0-*" }, "frameworks": { From f96ba3a254196395de248e44340c4b391990a239 Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 25 Oct 2016 14:31:37 -0700 Subject: [PATCH 426/597] Add extension method for AcceptAsync with timeout - Update tests for Win7 and Win2008R2 specific behaviour for caching responses without content-type --- .../Properties/AssemblyInfo.cs | 2 +- .../AuthenticationTests.cs | 18 +-- .../HttpsTests.cs | 10 +- .../OpaqueUpgradeTests.cs | 8 +- .../RequestBodyTests.cs | 26 ++-- .../RequestHeaderTests.cs | 6 +- .../RequestTests.cs | 18 +-- .../ResponseBodyTests.cs | 54 ++++---- .../ResponseCachingTests.cs | 123 +++++++++++------- .../ResponseHeaderTests.cs | 34 ++--- .../ResponseSendFileTests.cs | 62 ++++----- .../ResponseTests.cs | 12 +- .../ServerTests.cs | 28 ++-- .../Utilities.cs | 42 +++++- .../WebSocketTests.cs | 6 +- .../project.json | 8 ++ 16 files changed, 268 insertions(+), 189 deletions(-) diff --git a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs index 76feceeff0..78c1309651 100644 --- a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs @@ -8,4 +8,4 @@ using System.Resources; [assembly: NeutralResourcesLanguage("en-us")] [assembly: AssemblyCompany("Microsoft Corporation.")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs index 93b21417e8..dc7fb92160 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs @@ -29,7 +29,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); Assert.Equal(authType, context.Response.AuthenticationChallenges); @@ -54,7 +54,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var contextTask = server.AcceptAsync(); // Fails when the server shuts down, the challenge happens internally. + var contextTask = server.AcceptAsync(Utilities.DefaultTimeout); // Fails when the server shuts down, the challenge happens internally. var response = await responseTask; Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); @@ -74,7 +74,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); Assert.Equal(authType, context.Response.AuthenticationChallenges); @@ -101,7 +101,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); Assert.Equal(authType, context.Response.AuthenticationChallenges); @@ -127,14 +127,14 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); Assert.Equal(authType, context.Response.AuthenticationChallenges); context.Response.StatusCode = 401; context.Dispose(); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); Assert.Equal(authType, context.Response.AuthenticationChallenges); @@ -158,7 +158,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); Assert.Equal(authType, context.Response.AuthenticationChallenges); @@ -178,7 +178,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, useDefaultCredentials: true); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.NotNull(context.User); Assert.True(context.User.Identity.IsAuthenticated); Assert.Equal(AuthenticationSchemes.Kerberos, context.Response.AuthenticationChallenges); @@ -198,7 +198,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.NotNull(context.User); Assert.False(context.User.Identity.IsAuthenticated); Assert.Equal(AuthenticationSchemes.Kerberos, context.Response.AuthenticationChallenges); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index 58bf36998c..da34f91cfe 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(Address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); string response = await responseTask; @@ -38,7 +38,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(Address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.ContentLength = body.Length; await context.Response.Body.WriteAsync(body, 0, body.Length); @@ -56,7 +56,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(Address, "Hello World"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); string input = new StreamReader(context.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); context.Response.ContentLength = 11; @@ -77,7 +77,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(Address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cert = await context.Request.GetClientCertificateAsync(); Assert.Null(cert); context.Dispose(); @@ -96,7 +96,7 @@ namespace Microsoft.Net.Http.Server Assert.NotNull(clientCert); Task responseTask = SendRequestAsync(Address, clientCert); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cert = await context.Request.GetClientCertificateAsync(); Assert.NotNull(cert); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs index 987352df62..6027313f6d 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.Body.Write(body, 0, body.Length); @@ -45,7 +45,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendOpaqueRequestAsync("GET", address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.True(context.IsUpgradableRequest); context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket Stream serverStream = await context.UpgradeAsync(); @@ -89,7 +89,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendOpaqueRequestAsync(method, address, extraHeader); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.True(context.IsUpgradableRequest); context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket Stream serverStream = await context.UpgradeAsync(); @@ -129,7 +129,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServer(out address)) { var clientTask = SendOpaqueRequestAsync(method, address, extraHeader); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.False(context.IsUpgradableRequest); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs index 87b6d62dbf..6c801f80b7 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs @@ -24,7 +24,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[100]; int read = context.Request.Body.Read(input, 0, input.Length); context.Response.ContentLength = read; @@ -43,7 +43,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[100]; int read = await context.Request.Body.ReadAsync(input, 0, input.Length); context.Response.ContentLength = read; @@ -62,7 +62,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[100]; int read = context.Request.Body.EndRead(context.Request.Body.BeginRead(input, 0, input.Length, null, null)); context.Response.ContentLength = read; @@ -82,7 +82,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[100]; Assert.Throws("buffer", () => context.Request.Body.Read(null, 0, 1)); Assert.Throws("offset", () => context.Request.Body.Read(input, -1, 1)); @@ -107,7 +107,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; int read = context.Request.Body.Read(input, 0, input.Length); Assert.Equal(5, read); @@ -130,7 +130,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; int read = await context.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(5, read); @@ -152,7 +152,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendSocketRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[11]; int read = await context.Request.Body.ReadAsync(input, 0, input.Length); Assert.Equal(10, read); @@ -178,7 +178,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); @@ -203,7 +203,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); @@ -227,7 +227,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(5)); @@ -252,7 +252,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); @@ -277,7 +277,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, content); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; var cts = new CancellationTokenSource(); int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token); @@ -305,7 +305,7 @@ namespace Microsoft.Net.Http.Server var client = new HttpClient(); var responseTask = client.PostAsync(address, content); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; int read = await context.Request.Body.ReadAsync(input, 0, input.Length, context.DisconnectToken); Assert.False(context.DisconnectToken.IsCancellationRequested); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs index 2511e80d28..89457057fe 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var requestHeaders = context.Request.Headers; // NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point. // Assert.Equal(2, requestHeaders.Count); @@ -48,7 +48,7 @@ namespace Microsoft.Net.Http.Server string[] customValues = new string[] { "custom1, and custom2", "custom3" }; Task responseTask = SendRequestAsync(address, "Custom-Header", customValues); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var requestHeaders = context.Request.Headers; Assert.Equal(4, requestHeaders.Count); Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); @@ -75,7 +75,7 @@ namespace Microsoft.Net.Http.Server string[] customValues = new string[] { "custom1, and custom测试2", "custom3" }; Task responseTask = SendRequestAsync(address, "Custom-Header", customValues); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var requestHeaders = context.Request.Headers; Assert.Equal(4, requestHeaders.Count); Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs index f86e9a1124..d907e92e3b 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(root + "/basepath/SomePath?SomeQuery"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); // General fields var request = context.Request; @@ -66,7 +66,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(root + requestPath); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); // General fields var request = context.Request; @@ -94,7 +94,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) { var responseTask = SendSocketRequestAsync(root, requestPath); - var contextTask = server.AcceptAsync(); + var contextTask = server.AcceptAsync(Utilities.DefaultTimeout); var response = await responseTask; var responseStatusCode = response.Substring(9); // Skip "HTTP/1.1 " Assert.Equal("400", responseStatusCode); @@ -108,7 +108,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) { var responseTask = SendSocketRequestAsync(root, "/%252F"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Equal("/%2F", context.Request.Path); } } @@ -120,7 +120,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) { var responseTask = SendSocketRequestAsync(root, "*", "OPTIONS"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Equal("", context.Request.PathBase); Assert.Equal("", context.Request.Path); Assert.Equal("*", context.Request.RawUrl); @@ -159,7 +159,7 @@ namespace Microsoft.Net.Http.Server Task responseTask = SendRequestAsync(root + requestUri); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var request = context.Request; Assert.Equal(expectedPath, request.Path); @@ -202,7 +202,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) { var responseTask = SendSocketRequestAsync(root, "/" + requestPath); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); actualPath = context.Request.Path; context.Dispose(); @@ -227,7 +227,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) { var responseTask = SendSocketRequestAsync(root, requestPath); - var contextTask = server.AcceptAsync(); + var contextTask = server.AcceptAsync(Utilities.DefaultTimeout); var response = await responseTask; Assert.Equal("400", response.Substring(9)); @@ -252,7 +252,7 @@ namespace Microsoft.Net.Http.Server using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) { var responseTask = SendSocketRequestAsync(root, requestPath); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Equal(expectedPath, context.Request.Path); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 5177445589..67df513777 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -24,7 +24,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Body.Write(new byte[10], 0, 10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); @@ -47,7 +47,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Body.Write(new byte[10], 0, 10); context.Response.Body.Flush(); await context.Response.Body.WriteAsync(new byte[10], 0, 10); @@ -70,7 +70,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["transfeR-Encoding"] = "CHunked"; Stream stream = context.Response.Body; var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); @@ -95,7 +95,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 30 "; var stream = context.Response.Body; #if NET451 @@ -126,12 +126,12 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); #if !NETCOREAPP1_1 // HttpClient retries the request because it didn't get a response. - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); #endif @@ -147,7 +147,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Response.Body.Write(new byte[5], 0, 5); context.Dispose(); @@ -164,7 +164,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[5], 0, 5); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); @@ -182,7 +182,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[10], 0, 10); Assert.Throws(() => context.Response.Body.Write(new byte[6], 0, 6)); @@ -207,7 +207,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Body.Write(new byte[10], 0, 0); Assert.True(context.Response.HasStarted); await context.Response.Body.WriteAsync(new byte[10], 0, 0); @@ -231,7 +231,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); // First write sends headers await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); @@ -252,7 +252,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(10)); // First write sends headers @@ -275,7 +275,7 @@ namespace Microsoft.Net.Http.Server server.Settings.ThrowWriteExceptions = true; var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -284,7 +284,7 @@ namespace Microsoft.Net.Http.Server context.Dispose(); #if NET451 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -304,7 +304,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -313,7 +313,7 @@ namespace Microsoft.Net.Http.Server context.Dispose(); #if NET451 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -334,7 +334,7 @@ namespace Microsoft.Net.Http.Server server.Settings.ThrowWriteExceptions = true; var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); // First write sends headers await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); @@ -355,7 +355,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); // First write sends headers await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); @@ -378,7 +378,7 @@ namespace Microsoft.Net.Http.Server var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); await Assert.ThrowsAsync(() => responseTask); @@ -408,7 +408,7 @@ namespace Microsoft.Net.Http.Server var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); @@ -439,7 +439,7 @@ namespace Microsoft.Net.Http.Server var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); await Assert.ThrowsAsync(() => responseTask); @@ -462,7 +462,7 @@ namespace Microsoft.Net.Http.Server var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); await Assert.ThrowsAsync(() => responseTask); @@ -488,7 +488,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers context.Response.Body.Write(new byte[10], 0, 10); @@ -522,7 +522,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers await context.Response.Body.WriteAsync(new byte[10], 0, 10); @@ -555,7 +555,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers context.Response.Body.Write(new byte[10], 0, 10); @@ -585,7 +585,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers await context.Response.Body.WriteAsync(new byte[10], 0, 10); @@ -593,7 +593,7 @@ namespace Microsoft.Net.Http.Server response.EnsureSuccessStatusCode(); response.Dispose(); } - + Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. for (int i = 0; i < 10; i++) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index ce797fc9a0..5494b6a5de 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -24,6 +24,7 @@ namespace Microsoft.Net.Http.Server } [ConditionalFact] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win2008R2, WindowsVersions.Win7, SkipReason = "Content type not required for caching on Win7 and Win2008R2.")] public async Task Caching_SetTtlWithoutContentType_NotCached() { string address; @@ -31,7 +32,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -44,7 +45,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -57,6 +58,38 @@ namespace Microsoft.Net.Http.Server } } + [ConditionalFact] + public async Task Caching_SetTtlWithoutContentType_Cached_OnWin7AndWin2008R2() + { + if (Utilities.IsWin8orLater) + { + return; + } + + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Response.Headers["x-request-count"] = "1"; + // Http.sys does not require a content-type to cache on Win7 and Win2008R2 + context.Response.CacheTtl = TimeSpan.FromSeconds(10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); + } + } + [ConditionalFact] public async Task Caching_SetTtlWithContentType_Cached() { @@ -65,7 +98,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -94,7 +127,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -125,7 +158,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.Headers["age"] = "12345"; @@ -157,7 +190,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(0); @@ -170,7 +203,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -191,7 +224,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromMilliseconds(900); @@ -204,7 +237,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -225,7 +258,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(-10); @@ -238,7 +271,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -259,7 +292,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.MaxValue; @@ -286,7 +319,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 10; @@ -317,7 +350,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 10; @@ -348,7 +381,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -362,7 +395,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; context.Dispose(); @@ -381,7 +414,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -396,7 +429,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; context.Dispose(); @@ -415,7 +448,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 10; @@ -446,7 +479,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -460,7 +493,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; context.Dispose(); @@ -479,7 +512,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength =_fileLength; @@ -520,7 +553,7 @@ namespace Microsoft.Net.Http.Server var responseTask = SendRequestAsync(address + status); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.StatusCode = status; context.Response.Headers["x-request-count"] = status.ToString(); context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache @@ -571,7 +604,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, method); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = context.Request.Method + "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -584,7 +617,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address, method); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = context.Request.Method + "2"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -597,7 +630,7 @@ namespace Microsoft.Net.Http.Server } } - // RFC violation. http://tools.ietf.org/html/rfc7234#section-4.4 + // RFC violation. http://tools.ietf.org/html/rfc7234#section-4.4 // "A cache MUST invalidate the effective Request URI ... when a non-error status code // is received in response to an unsafe request method." [ConditionalTheory] @@ -630,7 +663,7 @@ namespace Microsoft.Net.Http.Server // Cache the first response var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = context.Request.Method + "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -644,7 +677,7 @@ namespace Microsoft.Net.Http.Server // Try to clear the cache with a second request responseTask = SendRequestAsync(address, method); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = context.Request.Method + "2"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Dispose(); @@ -675,7 +708,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "x-vary", "vary1"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.Headers["vary"] = "x-vary"; @@ -706,7 +739,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -719,7 +752,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Dispose(); @@ -740,7 +773,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -753,7 +786,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123"); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "2"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Dispose(); @@ -776,7 +809,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "Pragma", "no-cache"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -805,7 +838,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -833,7 +866,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "Cache-Control", "no-cache"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -861,7 +894,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -889,7 +922,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -917,7 +950,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); @@ -944,7 +977,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "GET", "Range", "bytes=0-10"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.StatusCode = 206; context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache @@ -961,7 +994,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address, "GET", "Range", "bytes=0-10"); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.StatusCode = 206; context.Response.Headers["x-request-count"] = "2"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache @@ -988,7 +1021,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 100; @@ -1018,7 +1051,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 100; @@ -1047,7 +1080,7 @@ namespace Microsoft.Net.Http.Server var responseLength = _fileLength / 2; // Make sure it handles partial files. var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = responseLength; @@ -1079,7 +1112,7 @@ namespace Microsoft.Net.Http.Server var responseLength = _fileLength / 2; // Make sure it handles partial files. var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = responseLength; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs index a485071fd6..69c918b6c9 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs @@ -24,7 +24,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -46,7 +46,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, usehttp11: false); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -69,7 +69,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendHeadRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -91,7 +91,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendHeadRequestAsync(address, usehttp11: false); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -114,7 +114,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendHeadRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.ContentLength = 20; context.Dispose(); @@ -137,7 +137,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.StatusCode = 204; // No Content context.Dispose(); @@ -160,7 +160,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendHeadRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.StatusCode = 204; // No Content context.Dispose(); @@ -184,7 +184,7 @@ namespace Microsoft.Net.Http.Server WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; responseHeaders["WWW-Authenticate"] = "custom1"; context.Dispose(); @@ -209,7 +209,7 @@ namespace Microsoft.Net.Http.Server WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; responseHeaders["WWW-Authenticate"] = new[] { "custom1, and custom2", "custom3" }; context.Dispose(); @@ -238,7 +238,7 @@ namespace Microsoft.Net.Http.Server WebRequest request = WebRequest.Create(address); Task responseTask = request.GetResponseAsync(); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; responseHeaders["Custom-Header1"] = new[] { "custom1, and custom2", "custom3" }; context.Dispose(); @@ -266,7 +266,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; responseHeaders["Connection"] = "Close"; context.Dispose(); @@ -286,7 +286,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address, usehttp11: false); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -309,7 +309,7 @@ namespace Microsoft.Net.Http.Server request.Version = new Version(1, 0); Task responseTask = client.SendAsync(request); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; responseHeaders["Transfer-Encoding"] = "chunked"; var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n"); @@ -337,7 +337,7 @@ namespace Microsoft.Net.Http.Server // Http.Sys does not support 1.0 keep-alives. Task responseTask = SendRequestAsync(address, usehttp11: false, sendKeepAlive: true); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); HttpResponseMessage response = await responseTask; @@ -355,7 +355,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; responseHeaders["Custom1"] = new[] { "value1a", "value1b" }; @@ -391,7 +391,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; responseHeaders["Custom1"] = new[] { "value1a", "value1b" }; @@ -445,7 +445,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs index af06647383..f5e7128531 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.Net.Http.Server private readonly string AbsoluteFilePath; private readonly string RelativeFilePath; private readonly long FileLength; - + public ResponseSendFileTests() { AbsoluteFilePath = Directory.GetFiles(Directory.GetCurrentDirectory()).First(); @@ -34,16 +34,16 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); - await Assert.ThrowsAsync(() => + var context = await server.AcceptAsync(Utilities.DefaultTimeout); + await Assert.ThrowsAsync(() => context.Response.SendFileAsync("Missing.txt", 0, null, CancellationToken.None)); context.Dispose(); - + var response = await responseTask; response.EnsureSuccessStatusCode(); } } - + [ConditionalFact] public async Task ResponseSendFile_NoHeaders_DefaultsToChunked() { @@ -52,7 +52,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -73,7 +73,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await context.Response.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -94,7 +94,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -115,7 +115,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); context.Dispose(); @@ -137,7 +137,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await context.Response.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None); context.Dispose(); @@ -158,7 +158,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await Assert.ThrowsAsync( () => context.Response.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None)); context.Dispose(); @@ -176,7 +176,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await Assert.ThrowsAsync( () => context.Response.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None)); context.Dispose(); @@ -194,7 +194,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); context.Dispose(); @@ -219,7 +219,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); await context.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None); Assert.True(context.Response.HasStarted); await context.Response.Body.WriteAsync(new byte[10], 0, 10, CancellationToken.None); @@ -243,7 +243,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = FileLength.ToString(); await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); @@ -265,7 +265,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = "10"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None); context.Dispose(); @@ -288,7 +288,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = "0"; await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None); context.Dispose(); @@ -311,7 +311,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); // First write sends headers await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); @@ -332,7 +332,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(10)); // First write sends headers @@ -355,7 +355,7 @@ namespace Microsoft.Net.Http.Server server.Settings.ThrowWriteExceptions = true; var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -364,7 +364,7 @@ namespace Microsoft.Net.Http.Server context.Dispose(); #if NET451 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -384,7 +384,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -393,7 +393,7 @@ namespace Microsoft.Net.Http.Server context.Dispose(); #if NET451 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); cts.Cancel(); // First write sends headers @@ -414,7 +414,7 @@ namespace Microsoft.Net.Http.Server server.Settings.ThrowWriteExceptions = true; var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); // First write sends headers await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); @@ -435,7 +435,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var cts = new CancellationTokenSource(); // First write sends headers await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); @@ -458,7 +458,7 @@ namespace Microsoft.Net.Http.Server var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); @@ -490,7 +490,7 @@ namespace Microsoft.Net.Http.Server var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); await Assert.ThrowsAsync(() => responseTask); @@ -504,7 +504,7 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact] + [ConditionalFact(Skip = "Tests hanging: https://github.com/aspnet/WebListener/issues/270")] public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeSecondSend_SendThrows() { string address; @@ -516,7 +516,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); @@ -538,7 +538,7 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact] + [ConditionalFact(Skip = "Tests hanging: https://github.com/aspnet/WebListener/issues/270")] public async Task ResponseSendFile_ClientDisconnectsBeforeSecondSend_SendCompletesSilently() { string address; @@ -549,7 +549,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address, HttpCompletionOption.ResponseHeadersRead); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs index 0fab49a9ae..cc43f1f356 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Equal(200, context.Response.StatusCode); context.Dispose(); @@ -40,7 +40,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.StatusCode = 201; // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value context.Dispose(); @@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.StatusCode = 201; context.Response.ReasonPhrase = "CustomReasonPhrase"; // TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value @@ -83,7 +83,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.StatusCode = 901; context.Dispose(); @@ -102,7 +102,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Throws(() => { context.Response.StatusCode = 100; }); context.Dispose(); @@ -118,7 +118,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Throws(() => { context.Response.StatusCode = 0; }); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs index cc5899745e..3dab88abbb 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs @@ -24,7 +24,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); var response = await responseTask; @@ -40,7 +40,7 @@ namespace Microsoft.Net.Http.Server { Task responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.ContentLength = 11; using (var writer = new StreamWriter(context.Response.Body)) { @@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address, "Hello World"); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); string input = new StreamReader(context.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); context.Response.ContentLength = 11; @@ -87,7 +87,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); @@ -118,7 +118,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); client.CancelPendingRequests(); await Assert.ThrowsAsync(() => responseTask); @@ -149,7 +149,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = client.GetAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); var response = await responseTask; @@ -178,7 +178,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); @@ -188,7 +188,7 @@ namespace Microsoft.Net.Http.Server Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); #if !NETCOREAPP1_1 // HttpClient re-tries the request because it doesn't know if the request was received. - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Abort(); #endif await Assert.ThrowsAsync(() => responseTask); @@ -206,7 +206,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.False(ct.IsCancellationRequested, "IsCancellationRequested"); @@ -237,7 +237,7 @@ namespace Microsoft.Net.Http.Server server.Settings.RequestQueueLimit = 1001; var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Dispose(); var response = await responseTask; @@ -253,7 +253,7 @@ namespace Microsoft.Net.Http.Server { var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Equal(string.Empty, context.Request.PathBase); Assert.Equal("/", context.Request.Path); context.Dispose(); @@ -266,7 +266,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Equal("/pathbase", context.Request.PathBase); Assert.Equal("/", context.Request.Path); context.Dispose(); @@ -286,7 +286,7 @@ namespace Microsoft.Net.Http.Server server.Settings.UrlPrefixes.Add(address); var responseTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Equal("/pathbase", context.Request.PathBase); Assert.Equal("/", context.Request.Path); context.Dispose(); @@ -298,7 +298,7 @@ namespace Microsoft.Net.Http.Server responseTask = SendRequestAsync(address); - context = await server.AcceptAsync(); + context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.Equal(string.Empty, context.Request.PathBase); Assert.Equal("/pathbase/", context.Request.Path); context.Dispose(); diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs index 0d5066f752..65e4ffe3ec 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs @@ -2,19 +2,37 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Internal; namespace Microsoft.Net.Http.Server { internal static class Utilities { - // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free - // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in + // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free + // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in // Microsoft.AspNetCore.Server.WebListener. private const int BasePort = 8001; private const int MaxPort = 11000; private static int NextPort = BasePort; private static object PortLock = new object(); + internal static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(15); + // Minimum support for Windows 7 is assumed. + internal static readonly bool IsWin8orLater; + + static Utilities() + { + var win8Version = new Version(6, 2); + +#if NET451 + IsWin8orLater = (Environment.OSVersion.Version >= win8Version); +#else + IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version); +#endif + } + internal static WebListener CreateHttpAuthServer(AuthenticationSchemes authScheme, bool allowAnonymos, out string baseAddress) { var listener = CreateHttpServer(out baseAddress); @@ -74,5 +92,25 @@ namespace Microsoft.Net.Http.Server listener.Start(); return listener; } + + /// + /// AcceptAsync extension with timeout. This extension should be used in all tests to prevent + /// unexpected hangs when a request does not arrive. + /// + internal static async Task AcceptAsync(this WebListener server, TimeSpan timeout) + { + var acceptTask = server.AcceptAsync(); + var completedTask = await Task.WhenAny(acceptTask, Task.Delay(timeout)); + + if (completedTask == acceptTask) + { + return await acceptTask; + } + else + { + server.Dispose(); + throw new TimeoutException("AcceptAsync has timed out."); + } + } } } diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs index eadc50f7cf..5aa8990690 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendRequestAsync(address); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] body = Encoding.UTF8.GetBytes("Hello World"); context.Response.Body.Write(body, 0, body.Length); @@ -43,7 +43,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.True(context.IsUpgradableRequest); WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); WebSocket clientWebSocket = await clientTask; @@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Server { Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); - var context = await server.AcceptAsync(); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); Assert.True(context.IsWebSocketRequest); WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); WebSocket clientWebSocket = await clientTask; diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 66007106c1..090e5e1874 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -1,5 +1,9 @@ { "testRunner": "xunit", + "buildOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", "Microsoft.AspNetCore.Testing": "1.1.0-*", @@ -9,6 +13,10 @@ "frameworks": { "netcoreapp1.1": { "dependencies": { + "Microsoft.Extensions.RuntimeEnvironment.Sources": { + "type": "build", + "version": "1.1.0-*" + }, "Microsoft.NETCore.App": { "version": "1.1.0-*", "type": "platform" From b9462ebee0fd997c1e0116639a1f4945e5b895c5 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 26 Oct 2016 11:00:24 -0700 Subject: [PATCH 427/597] Update .travis.yml to link openssl correctly --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 60138360be..ef345733c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; brew link --force openssl; fi + - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - ./build.sh --quiet verify notifications: From 8414a65f6bafcbe896852b59d6dd485919902d37 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 11:34:17 -0800 Subject: [PATCH 428/597] Branching for 1.1.0 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 826a1f9035..6197c93176 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..24ca167cf6 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index f4208100eb..fea9ac64ad 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 9f538d9c152588a527a1ba6aadb39a0df5b346d8 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 9 Nov 2016 11:49:39 -0800 Subject: [PATCH 429/597] Disable flaky tests --- .../ResponseBodyTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs index 67df513777..136883613c 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs @@ -156,7 +156,7 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/WebListener/issues/263")] public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { string address; @@ -510,7 +510,7 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/WebListener/issues/263")] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWriteAsync_WriteThrows() { string address; From bbe3c76c5ab61c64b50da780b9ef4dcf2355075a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 9 Nov 2016 14:20:16 -0800 Subject: [PATCH 430/597] Updating versions to 1.2.0-* --- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 4 ++-- samples/SelfHostServer/project.json | 4 ++-- .../project.json | 12 +++++++----- src/Microsoft.Net.Http.Server/project.json | 8 ++++---- .../project.json | 4 ++-- .../project.json | 6 +++--- test/Microsoft.Net.Http.Server.Tests/project.json | 2 +- 8 files changed, 22 insertions(+), 20 deletions(-) diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 342ec5501e..3f020a9932 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -3,7 +3,7 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.Net.Http.Server": "1.1.0-*" + "Microsoft.Net.Http.Server": "1.2.0-*" }, "commands": { "sample": "HelloWorld" diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index e1cdd57484..06363d656c 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,7 +1,7 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.1.0-*" + "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", + "Microsoft.Extensions.Logging.Console": "1.2.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 19e696585d..ecef54f54c 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,7 +1,7 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.1.0-*" + "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", + "Microsoft.Extensions.Logging.Console": "1.2.0-*" }, "buildOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index a61e1ebbdc..8a6480fbf0 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "description": "ASP.NET Core HTTP server for Windows.", "packOptions": { "tags": [ @@ -8,13 +8,15 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Hosting": "1.1.0-*", + "Microsoft.AspNetCore.Hosting": "1.2.0-*", "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "build" }, - "Microsoft.Net.Http.Headers": "1.1.0-*", - "Microsoft.Net.Http.Server": "1.1.0-*", + "Microsoft.Net.Http.Headers": "1.2.0-*", + "Microsoft.Net.Http.Server": { + "target": "project" + }, "NETStandard.Library": "1.6.1-*" }, "buildOptions": { diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index 4a8052c6b3..aff1daacbd 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -1,5 +1,5 @@ { - "version": "1.1.0-*", + "version": "1.2.0-*", "description": ".NET HTTP server that uses the Windows HTTP Server API.", "packOptions": { "tags": [ @@ -8,8 +8,8 @@ ] }, "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", - "Microsoft.Extensions.Primitives": "1.1.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", + "Microsoft.Extensions.Primitives": "1.2.0-*", "NETStandard.Library": "1.6.1-*" }, "buildOptions": { @@ -33,7 +33,7 @@ "dependencies": { "Microsoft.Extensions.RuntimeEnvironment.Sources": { "type": "build", - "version": "1.1.0-*" + "version": "1.2.0-*" }, "System.Diagnostics.Contracts": "4.3.0-*", "System.Net.WebSockets": "4.3.0-*", diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index b27565038d..1dc65a1e43 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -6,8 +6,8 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Server.WebListener": "1.1.0-*", - "Microsoft.AspNetCore.Testing": "1.1.0-*", + "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", + "Microsoft.AspNetCore.Testing": "1.2.0-*", "xunit": "2.2.0-*" }, "frameworks": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 090e5e1874..246625dbd1 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -6,8 +6,8 @@ }, "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Testing": "1.1.0-*", - "Microsoft.Net.Http.Server": "1.1.0-*", + "Microsoft.AspNetCore.Testing": "1.2.0-*", + "Microsoft.Net.Http.Server": "1.2.0-*", "xunit": "2.2.0-*" }, "frameworks": { @@ -15,7 +15,7 @@ "dependencies": { "Microsoft.Extensions.RuntimeEnvironment.Sources": { "type": "build", - "version": "1.1.0-*" + "version": "1.2.0-*" }, "Microsoft.NETCore.App": { "version": "1.1.0-*", diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index a4fc014661..6259da24ed 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -2,7 +2,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "1.1.0-*", + "Microsoft.Net.Http.Server": "1.2.0-*", "xunit": "2.2.0-*" }, "frameworks": { From 912feb63b710416790cc610d660105b43a6071f0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 18 Nov 2016 10:56:12 -0800 Subject: [PATCH 431/597] Clean tmp folder after unzipping KoreBuild --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index f4208100eb..4fd7ede788 100755 --- a/build.sh +++ b/build.sh @@ -38,7 +38,7 @@ if test ! -d $buildFolder; then chmod +x $buildFile # Cleanup - if test ! -d $tempFolder; then + if test -d $tempFolder; then rm -rf $tempFolder fi fi From 6d10c56a49e26a038c20e9e876201af8d8931124 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 23 Nov 2016 15:59:14 -0800 Subject: [PATCH 432/597] Pin global.json SDK to 1.0.0-preview2-1-003177. --- global.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index ec2e704f70..67e54ff84b 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,9 @@ { - "projects": ["src", "test"] -} + "projects": [ + "src", + "test" + ], + "sdk": { + "version": "1.0.0-preview2-1-003177" + } +} \ No newline at end of file From b91b9872ce48134de0da60c002d739dc2d1206b8 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 8 Dec 2016 10:03:29 -0800 Subject: [PATCH 433/597] Update .travis.yml osx image to xcode7.3. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ef345733c9..0dfc19b8b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ mono: os: - linux - osx -osx_image: xcode7.1 +osx_image: xcode7.3 branches: only: - master From 3489cf8c232b813768bb2df120c131a65d632bf0 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Mon, 12 Dec 2016 00:41:34 -0800 Subject: [PATCH 434/597] Removed packages list in NuGetPackageVerifier.json --- NuGetPackageVerifier.json | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 7ae83febd7..b153ab1515 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,14 +1,5 @@ { - "adx": { // Packages written by the ADX team and that ship on NuGet.org - "rules": [ - "AdxVerificationCompositeRule" - ], - "packages": { - "Microsoft.AspNetCore.Server.WebListener": { }, - "Microsoft.Net.Http.Server": { } - } - }, - "Default": { // Ru les to run for packages not listed in any other set. + "Default": { "rules": [ "DefaultCompositeRule" ] From 42297c152b383fadd02a8b03b534ea258a284766 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 5 Dec 2016 09:04:09 -0800 Subject: [PATCH 435/597] Updating to 4.4 CoreFx packages --- global.json | 2 +- samples/HelloWorld/project.json | 2 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/project.json | 2 +- .../project.json | 4 ++-- src/Microsoft.Net.Http.Server/project.json | 12 ++++++------ .../project.json | 6 +++--- .../project.json | 6 +++--- test/Microsoft.Net.Http.Server.Tests/project.json | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/global.json b/global.json index 67e54ff84b..ec96aa7abe 100644 --- a/global.json +++ b/global.json @@ -4,6 +4,6 @@ "test" ], "sdk": { - "version": "1.0.0-preview2-1-003177" + "version": "1.0.0-preview2-1-003180" } } \ No newline at end of file diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json index 3f020a9932..2d1231fd72 100644 --- a/samples/HelloWorld/project.json +++ b/samples/HelloWorld/project.json @@ -13,7 +13,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index 06363d656c..f67b728169 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -14,7 +14,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index ecef54f54c..4714c2321e 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -14,7 +14,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json index 8a6480fbf0..fbf6de302c 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ b/src/Microsoft.AspNetCore.Server.WebListener/project.json @@ -17,7 +17,7 @@ "Microsoft.Net.Http.Server": { "target": "project" }, - "NETStandard.Library": "1.6.1-*" + "NETStandard.Library": "1.6.2-*" }, "buildOptions": { "allowUnsafe": true, @@ -32,7 +32,7 @@ "net451": {}, "netstandard1.3": { "dependencies": { - "System.Security.Claims": "4.3.0-*" + "System.Security.Claims": "4.4.0-*" } } } diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.Net.Http.Server/project.json index aff1daacbd..29f16b72a6 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.Net.Http.Server/project.json @@ -10,7 +10,7 @@ "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", "Microsoft.Extensions.Primitives": "1.2.0-*", - "NETStandard.Library": "1.6.1-*" + "NETStandard.Library": "1.6.2-*" }, "buildOptions": { "allowUnsafe": true, @@ -35,11 +35,11 @@ "type": "build", "version": "1.2.0-*" }, - "System.Diagnostics.Contracts": "4.3.0-*", - "System.Net.WebSockets": "4.3.0-*", - "System.Security.Claims": "4.3.0-*", - "System.Security.Principal.Windows": "4.3.0-*", - "System.Threading.Overlapped": "4.3.0-*" + "System.Diagnostics.Contracts": "4.4.0-*", + "System.Net.WebSockets": "4.4.0-*", + "System.Security.Claims": "4.4.0-*", + "System.Security.Principal.Windows": "4.4.0-*", + "System.Threading.Overlapped": "4.4.0-*" } } } diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json index 1dc65a1e43..c2443aa47b 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json @@ -14,11 +14,11 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" }, - "System.Net.Http.WinHttpHandler": "4.3.0-*", - "System.Net.WebSockets.Client": "4.3.0-*" + "System.Net.Http.WinHttpHandler": "4.4.0-*", + "System.Net.WebSockets.Client": "4.4.0-*" } }, "net451": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json index 246625dbd1..f245f631b6 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json @@ -18,11 +18,11 @@ "version": "1.2.0-*" }, "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" }, - "System.Net.Http.WinHttpHandler": "4.3.0-*", - "System.Net.WebSockets.Client": "4.3.0-*" + "System.Net.Http.WinHttpHandler": "4.4.0-*", + "System.Net.WebSockets.Client": "4.4.0-*" } }, "net451": { diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.Net.Http.Server.Tests/project.json index 6259da24ed..1786eefe1f 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.Net.Http.Server.Tests/project.json @@ -9,7 +9,7 @@ "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.1.0-*", + "version": "1.2.0-*", "type": "platform" } } From 89ca7ed08059e0f429661c7e78bbdef4d08ee1ea Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Thu, 22 Dec 2016 18:50:47 -0800 Subject: [PATCH 436/597] Disable tests that hang after update to CoreFx 4.4. --- .../HttpsTests.cs | 15 ++++++++++----- .../HttpsTests.cs | 15 ++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs index 2309b9cf7d..058ab551f9 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -17,7 +17,8 @@ namespace Microsoft.AspNetCore.Server.WebListener { private const string Address = "https://localhost:9090/"; - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_200OK_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -30,7 +31,8 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_SendHelloWorld_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -45,7 +47,8 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_EchoHelloWorld_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -63,7 +66,8 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { using (Utilities.CreateHttpsServer(async httpContext => @@ -80,7 +84,8 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertRequested_ClientCertPresent() { using (Utilities.CreateHttpsServer(async httpContext => diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index da34f91cfe..ff8709377a 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -16,7 +16,8 @@ namespace Microsoft.Net.Http.Server // Note these tests can't use dynamic ports or run concurrently because the ssl cert must be pre-registered with a specific port. private const string Address = "https://localhost:9090/"; - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_200OK_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -31,7 +32,8 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_SendHelloWorld_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -49,7 +51,8 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_EchoHelloWorld_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -70,7 +73,8 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { using (var server = Utilities.CreateHttpsServer()) @@ -87,7 +91,8 @@ namespace Microsoft.Net.Http.Server } } - [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) + //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertRequested_ClientCertPresent() { using (var server = Utilities.CreateHttpsServer()) From fe8e3bbe67779ea9f241543b69af72f9bef0397f Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Fri, 23 Dec 2016 17:51:16 -0800 Subject: [PATCH 437/597] Revert "Disable tests that hang after update to CoreFx 4.4." This reverts commit 89ca7ed08059e0f429661c7e78bbdef4d08ee1ea. --- .../HttpsTests.cs | 15 +++++---------- .../HttpsTests.cs | 15 +++++---------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs index 058ab551f9..2309b9cf7d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs @@ -17,8 +17,7 @@ namespace Microsoft.AspNetCore.Server.WebListener { private const string Address = "https://localhost:9090/"; - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_200OK_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -31,8 +30,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_SendHelloWorld_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -47,8 +45,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_EchoHelloWorld_Success() { using (Utilities.CreateHttpsServer(httpContext => @@ -66,8 +63,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { using (Utilities.CreateHttpsServer(async httpContext => @@ -84,8 +80,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } } - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertRequested_ClientCertPresent() { using (Utilities.CreateHttpsServer(async httpContext => diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs index ff8709377a..da34f91cfe 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs @@ -16,8 +16,7 @@ namespace Microsoft.Net.Http.Server // Note these tests can't use dynamic ports or run concurrently because the ssl cert must be pre-registered with a specific port. private const string Address = "https://localhost:9090/"; - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_200OK_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -32,8 +31,7 @@ namespace Microsoft.Net.Http.Server } } - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_SendHelloWorld_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -51,8 +49,7 @@ namespace Microsoft.Net.Http.Server } } - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_EchoHelloWorld_Success() { using (var server = Utilities.CreateHttpsServer()) @@ -73,8 +70,7 @@ namespace Microsoft.Net.Http.Server } } - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertNotSent_ClientCertNotPresent() { using (var server = Utilities.CreateHttpsServer()) @@ -91,8 +87,7 @@ namespace Microsoft.Net.Http.Server } } - // Disabled due to SslStream hanging on write after update to CoreFx 4.4 (https://github.com/dotnet/corefx/issues/14698) - //[ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] + [ConditionalFact(Skip = "TODO: Add trait filtering support so these SSL tests don't get run on teamcity or the command line."), Trait("scheme", "https")] public async Task Https_ClientCertRequested_ClientCertPresent() { using (var server = Utilities.CreateHttpsServer()) From 4c388e89ce453a189aa861a40297a576aed14cdd Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 15 Dec 2016 12:46:16 -0800 Subject: [PATCH 438/597] #283 Merge packages, namespaces, test projects, and samples --- WebListener.sln | 45 +-- samples/HelloWorld/HelloWorld.xproj | 17 - samples/HelloWorld/Program.cs | 89 ----- .../HelloWorld/Properties/launchSettings.json | 9 - samples/HelloWorld/project.json | 22 -- samples/HotAddSample/Startup.cs | 3 +- samples/HotAddSample/project.json | 2 +- samples/SelfHostServer/Startup.cs | 3 +- samples/SelfHostServer/project.json | 2 +- .../AsyncAcceptContext.cs | 2 +- .../AuthenticationHandler.cs | 3 +- .../AuthenticationManager.cs | 2 +- .../AuthenticationSchemes.cs | 2 +- .../Constants.cs | 3 +- .../CustomDictionary.xml | 0 .../FeatureContext.cs | 3 +- .../HeaderDictionary.cs | 2 +- .../Helpers.cs | 2 +- .../Internal/WebListenerOptionsSetup.cs | 4 +- .../LogHelper.cs | 14 +- .../MessagePump.cs | 11 +- ...Microsoft.AspNetCore.Server.HttpSys.xproj} | 3 + .../NativeInterop/AddressFamily.cs | 2 +- .../NativeInterop/ComNetOS.cs | 2 +- .../NativeInterop/ContextAttribute.cs | 2 +- .../NativeInterop/CookedUrl.cs | 2 +- .../NativeInterop/DisconnectListener.cs | 2 +- .../NativeInterop/HeapAllocHandle.cs | 2 +- .../NativeInterop/HttpApi.cs | 2 +- .../NativeInterop/HttpRequestQueueV2Handle.cs | 2 +- .../NativeInterop/HttpServerSessionHandle.cs | 2 +- .../NativeInterop/HttpSysRequestHeader.cs | 2 +- .../NativeInterop/HttpSysResponseHeader.cs | 2 +- .../NativeInterop/HttpSysSettings.cs | 2 +- .../NativeInterop/IntPtrHelper.cs | 2 +- .../NativeInterop/NclUtilities.cs | 2 +- .../NativeInterop/RequestQueue.cs | 2 +- .../NativeInterop/SSPIHandle.cs | 2 +- .../NativeInterop/SafeLoadLibrary.cs | 2 +- .../NativeInterop/SafeLocalFree.cs | 2 +- .../SafeLocalFreeChannelBinding.cs | 2 +- .../NativeInterop/SafeLocalMemHandle.cs | 2 +- .../NativeInterop/SafeNativeOverlapped.cs | 2 +- .../NativeInterop/SchProtocols.cs | 2 +- .../NativeInterop/SecurityStatus.cs | 2 +- .../NativeInterop/ServerSession.cs | 2 +- .../NativeInterop/SocketAddress.cs | 2 +- .../NativeInterop/TokenBindingUtil.cs | 6 +- .../NativeInterop/UnsafeNativeMethods.cs | 2 +- .../NativeInterop/UrlGroup.cs | 2 +- .../Overlapped/DeferredDisposableLifetime.cs | 0 .../Overlapped/IDeferredDisposable.cs | 0 .../Overlapped/PreAllocatedOverlapped.cs | 0 .../Overlapped/ThreadPoolBoundHandle.cs | 0 .../ThreadPoolBoundHandleOverlapped.cs | 0 .../Properties/AssemblyInfo.cs | 2 +- .../Properties/Resources.Designer.cs | 206 ++++++++++++ .../RequestProcessing/BoundaryType.cs | 2 +- .../RequestProcessing/ClientCertLoader.cs | 2 +- .../RequestProcessing/HeaderCollection.cs | 2 +- .../RequestProcessing/HeaderEncoding.cs | 2 +- .../RequestProcessing/HeaderParser.cs | 2 +- .../RequestProcessing/HttpKnownHeaderNames.cs | 2 +- .../RequestProcessing/HttpReasonPhrase.cs | 7 +- .../RequestProcessing/NativeRequestContext.cs | 2 +- .../RequestProcessing/OpaqueStream.cs | 2 +- .../RequestProcessing/RawUrlHelper.cs | 2 +- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestContext.cs | 6 +- .../RequestHeaders.Generated.cs | 194 +++++------ .../RequestHeaders.Generated.tt | 15 +- .../RequestProcessing/RequestHeaders.cs | 2 +- .../RequestProcessing/RequestStream.cs | 2 +- .../RequestStreamAsyncResult.cs | 2 +- .../RequestProcessing/RequestUriBuilder.cs | 2 +- .../RequestProcessing/Response.cs | 14 +- .../RequestProcessing/ResponseBody.cs} | 8 +- .../ResponseStreamAsyncResult.cs | 12 +- .../RequestProcessing/SslStatus.cs | 2 +- .../Resources.resx | 0 .../ResponseStream.cs | 4 +- .../StandardFeatureCollection.cs | 3 +- .../TimeoutManager.cs | 2 +- .../UrlPrefix.cs | 2 +- .../UrlPrefixCollection.cs | 2 +- .../ValidationHelper.cs | 2 +- .../WebHostBuilderWebListenerExtensions.cs | 4 +- .../WebListener.cs | 9 +- .../WebListenerException.cs | 2 +- .../WebListenerOptions.cs | 3 +- .../WebListenerSettings.cs | 2 +- .../WebSocketHelpers.cs | 2 +- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 0 .../SafeHandleZeroOrMinusOneIsInvalid.cs | 0 .../fx/System/Net/WebSockets/CompatHelpers.cs | 0 .../fx/System/Net/WebSockets/README.md | 0 .../fx/System/Net/WebSockets/SR.cs | 0 .../Net/WebSockets/WebSocketValidate.cs | 0 .../System/Net/WebSockets/ManagedWebSocket.cs | 0 .../project.json | 20 +- .../Helpers.cs | 21 -- .../project.json | 39 --- src/Microsoft.Net.Http.Server/LogHelper.cs | 72 ---- .../Microsoft.Net.Http.Server.xproj | 17 - .../Properties/AssemblyInfo.cs | 11 - .../RequestProcessing/HttpStatusCode.cs | 311 ------------------ .../Resources.Designer.cs | 164 --------- .../AuthenticationTests.cs | 4 +- .../DummyApplication.cs | 2 +- .../HttpsTests.cs | 2 +- .../Listener}/AuthenticationTests.cs | 2 +- .../Listener}/HttpsTests.cs | 2 +- .../Listener}/OpaqueUpgradeTests.cs | 2 +- .../Listener}/RequestBodyTests.cs | 2 +- .../Listener}/RequestHeaderTests.cs | 2 +- .../Listener}/RequestTests.cs | 2 +- .../Listener}/ResponseBodyTests.cs | 2 +- .../Listener}/ResponseCachingTests.cs | 2 +- .../Listener}/ResponseHeaderTests.cs | 2 +- .../Listener}/ResponseSendFileTests.cs | 2 +- .../Listener}/ResponseTests.cs | 2 +- .../Listener}/ServerTests.cs | 2 +- .../Listener}/SkipOffDomainAttribute.cs | 2 +- .../Listener}/Utilities.cs | 2 +- .../Listener}/WebSocketTests.cs | 2 +- ...Core.Server.HttpSys.FunctionalTests.xproj} | 0 .../OpaqueUpgradeTests.cs | 2 +- .../Properties/AssemblyInfo.cs | 0 .../RequestBodyTests.cs | 2 +- .../RequestHeaderTests.cs | 2 +- .../RequestTests.cs | 3 +- .../ResponseBodyTests.cs | 2 +- .../ResponseCachingTests.cs | 2 +- .../ResponseHeaderTests.cs | 2 +- .../ResponseSendFileTests.cs | 2 +- .../ResponseTests.cs | 2 +- .../ServerTests.cs | 3 +- .../Utilities.cs | 3 +- .../WebSocketTests.cs | 2 +- .../project.json | 3 +- ...oft.AspNetCore.Server.HttpSys.Tests.xproj} | 0 .../UrlPrefixTests.cs | 2 +- .../project.json | 2 +- ...soft.Net.Http.Server.FunctionalTests.xproj | 20 -- .../Properties/AssemblyInfo.cs | 7 - .../project.json | 36 -- 146 files changed, 467 insertions(+), 1157 deletions(-) delete mode 100644 samples/HelloWorld/HelloWorld.xproj delete mode 100644 samples/HelloWorld/Program.cs delete mode 100644 samples/HelloWorld/Properties/launchSettings.json delete mode 100644 samples/HelloWorld/project.json rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/AsyncAcceptContext.cs (99%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/AuthenticationHandler.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/AuthenticationManager.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/AuthenticationSchemes.cs (91%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/Constants.cs (85%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/CustomDictionary.xml (100%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/FeatureContext.cs (99%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/HeaderDictionary.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/Helpers.cs (98%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/Internal/WebListenerOptionsSetup.cs (85%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/LogHelper.cs (84%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/MessagePump.cs (95%) rename src/{Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj => Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.xproj} (90%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/AddressFamily.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/ComNetOS.cs (93%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/ContextAttribute.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/CookedUrl.cs (97%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/DisconnectListener.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/HeapAllocHandle.cs (94%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/HttpApi.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/HttpRequestQueueV2Handle.cs (93%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/HttpServerSessionHandle.cs (96%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/HttpSysRequestHeader.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/HttpSysResponseHeader.cs (97%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/HttpSysSettings.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/IntPtrHelper.cs (91%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/NclUtilities.cs (91%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/RequestQueue.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SSPIHandle.cs (94%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SafeLoadLibrary.cs (96%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SafeLocalFree.cs (96%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SafeLocalFreeChannelBinding.cs (96%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SafeLocalMemHandle.cs (94%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SafeNativeOverlapped.cs (97%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SchProtocols.cs (97%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SecurityStatus.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/ServerSession.cs (95%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/SocketAddress.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/TokenBindingUtil.cs (94%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/UnsafeNativeMethods.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/NativeInterop/UrlGroup.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/Overlapped/DeferredDisposableLifetime.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/Overlapped/IDeferredDisposable.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/Overlapped/PreAllocatedOverlapped.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/Overlapped/ThreadPoolBoundHandle.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/Overlapped/ThreadPoolBoundHandleOverlapped.cs (100%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/Properties/AssemblyInfo.cs (56%) create mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/BoundaryType.cs (91%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/ClientCertLoader.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/HeaderCollection.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/HeaderEncoding.cs (96%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/HeaderParser.cs (97%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/HttpKnownHeaderNames.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/HttpReasonPhrase.cs (95%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/NativeRequestContext.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/OpaqueStream.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/RawUrlHelper.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/Request.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/RequestContext.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/RequestHeaders.Generated.cs (93%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/RequestHeaders.Generated.tt (95%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/RequestHeaders.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/RequestStream.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/RequestStreamAsyncResult.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/RequestUriBuilder.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/Response.cs (98%) rename src/{Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs => Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs} (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/ResponseStreamAsyncResult.cs (96%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/RequestProcessing/SslStatus.cs (85%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/Resources.resx (100%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/ResponseStream.cs (98%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/StandardFeatureCollection.cs (97%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/TimeoutManager.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/UrlPrefix.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/UrlPrefixCollection.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/ValidationHelper.cs (97%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/WebHostBuilderWebListenerExtensions.cs (94%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/WebListener.cs (97%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/WebListenerException.cs (96%) rename src/{Microsoft.AspNetCore.Server.WebListener => Microsoft.AspNetCore.Server.HttpSys}/WebListenerOptions.cs (93%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/WebListenerSettings.cs (98%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/WebSocketHelpers.cs (99%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/fx/System/Net/WebSockets/CompatHelpers.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/fx/System/Net/WebSockets/README.md (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/fx/System/Net/WebSockets/SR.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs (100%) rename src/{Microsoft.Net.Http.Server => Microsoft.AspNetCore.Server.HttpSys}/project.json (71%) delete mode 100644 src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs delete mode 100644 src/Microsoft.AspNetCore.Server.WebListener/project.json delete mode 100644 src/Microsoft.Net.Http.Server/LogHelper.cs delete mode 100644 src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj delete mode 100644 src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs delete mode 100644 src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs delete mode 100644 src/Microsoft.Net.Http.Server/Resources.Designer.cs rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/AuthenticationTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/DummyApplication.cs (95%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/HttpsTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/AuthenticationTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/HttpsTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/OpaqueUpgradeTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/RequestBodyTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/RequestHeaderTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/RequestTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/ResponseBodyTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/ResponseCachingTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/ResponseHeaderTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/ResponseSendFileTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/ResponseTests.cs (98%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/ServerTests.cs (99%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/SkipOffDomainAttribute.cs (94%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/Utilities.cs (98%) rename test/{Microsoft.Net.Http.Server.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener}/WebSocketTests.cs (98%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj} (100%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/OpaqueUpgradeTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/Properties/AssemblyInfo.cs (100%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/RequestBodyTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/RequestHeaderTests.cs (98%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/RequestTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/ResponseBodyTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/ResponseCachingTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/ResponseHeaderTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/ResponseSendFileTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/ResponseTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/ServerTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/Utilities.cs (97%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/WebSocketTests.cs (99%) rename test/{Microsoft.AspNetCore.Server.WebListener.FunctionalTests => Microsoft.AspNetCore.Server.HttpSys.FunctionalTests}/project.json (87%) rename test/{Microsoft.Net.Http.Server.Tests/Microsoft.Net.Http.Server.Tests.xproj => Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.xproj} (100%) rename test/{Microsoft.Net.Http.Server.Tests => Microsoft.AspNetCore.Server.HttpSys.Tests}/UrlPrefixTests.cs (98%) rename test/{Microsoft.Net.Http.Server.Tests => Microsoft.AspNetCore.Server.HttpSys.Tests}/project.json (85%) delete mode 100644 test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj delete mode 100644 test/Microsoft.Net.Http.Server.FunctionalTests/Properties/AssemblyInfo.cs delete mode 100644 test/Microsoft.Net.Http.Server.FunctionalTests/project.json diff --git a/WebListener.sln b/WebListener.sln index 5623786165..21d618b148 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -10,17 +10,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E183C826-1 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A1E31E3-2794-4CA3-B8E2-253E96BDE514}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server", "src\Microsoft.Net.Http.Server\Microsoft.Net.Http.Server.xproj", "{3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HelloWorld", "samples\HelloWorld\HelloWorld.xproj", "{6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}" -EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.xproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.WebListener.FunctionalTests", "test\Microsoft.AspNetCore.Server.WebListener.FunctionalTests\Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj", "{4492FF4C-9032-411D-853F-46B01755E504}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.HttpSys.FunctionalTests", "test\Microsoft.AspNetCore.Server.HttpSys.FunctionalTests\Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj", "{4492FF4C-9032-411D-853F-46B01755E504}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.WebListener", "src\Microsoft.AspNetCore.Server.WebListener\Microsoft.AspNetCore.Server.WebListener.xproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server.FunctionalTests", "test\Microsoft.Net.Http.Server.FunctionalTests\Microsoft.Net.Http.Server.FunctionalTests.xproj", "{DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.HttpSys", "src\Microsoft.AspNetCore.Server.HttpSys\Microsoft.AspNetCore.Server.HttpSys.xproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5E9B546C-17AC-4BDF-BCB3-5955D4755ED8}" ProjectSection(SolutionItems) = preProject @@ -29,7 +23,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HotAddSample", "samples\HotAddSample\HotAddSample.xproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Net.Http.Server.Tests", "test\Microsoft.Net.Http.Server.Tests\Microsoft.Net.Http.Server.Tests.xproj", "{E837249E-E666-4DF2-AFC3-7A4D70234F9F}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.HttpSys.Tests", "test\Microsoft.AspNetCore.Server.HttpSys.Tests\Microsoft.AspNetCore.Server.HttpSys.Tests.xproj", "{E837249E-E666-4DF2-AFC3-7A4D70234F9F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -51,26 +45,6 @@ Global {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8B828433-B333-4C19-96AE-00BFFF9D8841}.Release|x86.ActiveCfg = Release|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Debug|x86.ActiveCfg = Debug|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Any CPU.Build.0 = Release|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1}.Release|x86.ActiveCfg = Release|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Debug|x86.ActiveCfg = Debug|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Any CPU.Build.0 = Release|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4}.Release|x86.ActiveCfg = Release|Any CPU {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Any CPU.Build.0 = Debug|Any CPU {1236F93A-AC5C-4A77-9477-C88F040151CA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -101,16 +75,6 @@ Global {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|Mixed Platforms.Build.0 = Release|Any CPU {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}.Release|x86.ActiveCfg = Release|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Debug|x86.ActiveCfg = Debug|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Any CPU.Build.0 = Release|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1}.Release|x86.ActiveCfg = Release|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|Any CPU.Build.0 = Debug|Any CPU {8BFA392A-8B67-4454-916B-67C545EDFAEF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -141,12 +105,9 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {8B828433-B333-4C19-96AE-00BFFF9D8841} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} - {3F5212AA-E287-49DD-8CEC-44BF0A2AC9A1} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} - {6DAF3E6B-8E1B-4E6E-B9FE-7B1E5FDB7DB4} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {1236F93A-AC5C-4A77-9477-C88F040151CA} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {4492FF4C-9032-411D-853F-46B01755E504} = {E183C826-1360-4DFF-9994-F33CED5C8525} {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} - {DCB6E0B1-223D-44E6-8696-4767E5B6E6A1} = {E183C826-1360-4DFF-9994-F33CED5C8525} {8BFA392A-8B67-4454-916B-67C545EDFAEF} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {E837249E-E666-4DF2-AFC3-7A4D70234F9F} = {E183C826-1360-4DFF-9994-F33CED5C8525} EndGlobalSection diff --git a/samples/HelloWorld/HelloWorld.xproj b/samples/HelloWorld/HelloWorld.xproj deleted file mode 100644 index 45065516db..0000000000 --- a/samples/HelloWorld/HelloWorld.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 6daf3e6b-8e1b-4e6e-b9fe-7b1e5fdb7db4 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs deleted file mode 100644 index dac0e302bd..0000000000 --- a/samples/HelloWorld/Program.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Net.Http.Server; - -namespace HelloWorld -{ - public class Program - { - public static void Main(string[] args) - { - Run(args).Wait(); - } - - public static async Task Run(string[] args) - { - var settings = new WebListenerSettings(); - settings.UrlPrefixes.Add("http://localhost:8080"); - - using (WebListener listener = new WebListener(settings)) - { - listener.Start(); - - Console.WriteLine("Running..."); - while (true) - { - RequestContext context = await listener.AcceptAsync(); - Console.WriteLine("Accepted"); - - // Context: - // context.User; - // context.DisconnectToken - // context.Dispose() - // context.Abort(); - - // Request - // context.Request.ProtocolVersion - // context.Request.Headers - // context.Request.Method - // context.Request.Body - // Content-Length - long? - // Content-Type - string - // IsSecureConnection - // HasEntityBody - - // TODO: Request fields - // Content-Encoding - Encoding - // Host - // Client certs - GetCertAsync, CertErrors - // Cookies - // KeepAlive - // QueryString (parsed) - // RequestTraceIdentifier - // RawUrl - // URI - // IsWebSocketRequest - // LocalEndpoint vs LocalIP & LocalPort - // RemoteEndpoint vs RemoteIP & RemotePort - // AcceptTypes string[] - // ServiceName - // TransportContext - - // Response - byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); - - if (context.IsWebSocketRequest) - { - Console.WriteLine("WebSocket"); - WebSocket webSocket = await context.AcceptWebSocketAsync(); - await webSocket.SendAsync(new ArraySegment(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None); - await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Goodbye", CancellationToken.None); - webSocket.Dispose(); - } - else - { - Console.WriteLine("Hello World"); - context.Response.ContentLength = bytes.Length; - context.Response.ContentType = "text/plain"; - - context.Response.Body.Write(bytes, 0, bytes.Length); - context.Dispose(); - } - } - } - } - } -} \ No newline at end of file diff --git a/samples/HelloWorld/Properties/launchSettings.json b/samples/HelloWorld/Properties/launchSettings.json deleted file mode 100644 index f96a6f4415..0000000000 --- a/samples/HelloWorld/Properties/launchSettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "profiles": { - "HelloWorld": { - "commandName": "Project", - "launchBrowser": true, - "launchUrl": "http://localhost:8080" - } - } -} \ No newline at end of file diff --git a/samples/HelloWorld/project.json b/samples/HelloWorld/project.json deleted file mode 100644 index 2d1231fd72..0000000000 --- a/samples/HelloWorld/project.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "buildOptions": { - "emitEntryPoint": true - }, - "dependencies": { - "Microsoft.Net.Http.Server": "1.2.0-*" - }, - "commands": { - "sample": "HelloWorld" - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - } -} \ No newline at end of file diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index a6cf016890..c3a75a32ef 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -2,10 +2,9 @@ using System; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Server.WebListener; +using Microsoft.AspNetCore.Server.HttpSys; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Server; namespace HotAddSample { diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json index f67b728169..e35173259b 100644 --- a/samples/HotAddSample/project.json +++ b/samples/HotAddSample/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", + "Microsoft.AspNetCore.Server.HttpSys": "1.2.0-*", "Microsoft.Extensions.Logging.Console": "1.2.0-*" }, "buildOptions": { diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index c6a9fecf72..9647038bfd 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -5,10 +5,9 @@ using System.Threading; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Server.WebListener; +using Microsoft.AspNetCore.Server.HttpSys; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Server; namespace SelfHostServer { diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json index 4714c2321e..756b800031 100644 --- a/samples/SelfHostServer/project.json +++ b/samples/SelfHostServer/project.json @@ -1,6 +1,6 @@ { "dependencies": { - "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", + "Microsoft.AspNetCore.Server.HttpSys": "1.2.0-*", "Microsoft.Extensions.Logging.Console": "1.2.0-*" }, "buildOptions": { diff --git a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs index 608e46d990..5fbd001407 100644 --- a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs @@ -7,7 +7,7 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal unsafe class AsyncAcceptContext : IAsyncResult, IDisposable { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs similarity index 98% rename from src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs index d556fca274..81c030e30e 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs @@ -7,9 +7,8 @@ using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Extensions.Internal; -using Microsoft.Net.Http.Server; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { internal class AuthenticationHandler : IAuthenticationHandler { diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/AuthenticationManager.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs index 31b1b9b35a..e4b728dcd4 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs @@ -10,7 +10,7 @@ using System.Security.Claims; using System.Security.Principal; using Microsoft.Extensions.Primitives; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // See the native HTTP_SERVER_AUTHENTICATION_INFO structure documentation for additional information. // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364638(v=vs.85).aspx diff --git a/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationSchemes.cs similarity index 91% rename from src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationSchemes.cs index a531724e1c..3d82bdadc0 100644 --- a/src/Microsoft.Net.Http.Server/AuthenticationSchemes.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationSchemes.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // REVIEW: this appears to be very similar to System.Net.AuthenticationSchemes [Flags] diff --git a/src/Microsoft.Net.Http.Server/Constants.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs similarity index 85% rename from src/Microsoft.Net.Http.Server/Constants.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs index 866b87d965..f4b0b1884d 100644 --- a/src/Microsoft.Net.Http.Server/Constants.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class Constants { @@ -13,6 +13,7 @@ namespace Microsoft.Net.Http.Server internal const string Close = "close"; internal const string Zero = "0"; internal const string SchemeDelimiter = "://"; + internal const int Status101SwitchingProtocols = 101; internal static Version V1_0 = new Version(1, 0); internal static Version V1_1 = new Version(1, 1); diff --git a/src/Microsoft.Net.Http.Server/CustomDictionary.xml b/src/Microsoft.AspNetCore.Server.HttpSys/CustomDictionary.xml similarity index 100% rename from src/Microsoft.Net.Http.Server/CustomDictionary.xml rename to src/Microsoft.AspNetCore.Server.HttpSys/CustomDictionary.xml diff --git a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index d2a0bd57cb..867e1e55b3 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -16,9 +16,8 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Extensions.Internal; using Microsoft.Net.Http.Headers; -using Microsoft.Net.Http.Server; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { internal class FeatureContext : IHttpRequestFeature, diff --git a/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs index 6676fd8b99..fdc00eee2b 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/HeaderDictionary.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { /// /// Represents a wrapper for RequestHeaders and ResponseHeaders. diff --git a/src/Microsoft.Net.Http.Server/Helpers.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/Helpers.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs index fb79443195..9fee1c191a 100644 --- a/src/Microsoft.Net.Http.Server/Helpers.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class Helpers { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Internal/WebListenerOptionsSetup.cs similarity index 85% rename from src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Internal/WebListenerOptionsSetup.cs index b1664c9539..29aecb6878 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Internal/WebListenerOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Internal/WebListenerOptionsSetup.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace Microsoft.AspNetCore.Server.WebListener.Internal +namespace Microsoft.AspNetCore.Server.HttpSys.Internal { public class WebListenerOptionsSetup : IConfigureOptions { @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.Internal public void Configure(WebListenerOptions options) { - options.ListenerSettings.Logger = _loggerFactory.CreateLogger(); + options.ListenerSettings.Logger = _loggerFactory.CreateLogger(); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs b/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs similarity index 84% rename from src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs index 70a819396b..6442e0842b 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/LogHelper.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs @@ -5,7 +5,7 @@ using System; using System.Diagnostics; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class LogHelper { @@ -31,6 +31,18 @@ namespace Microsoft.AspNetCore.Server.WebListener } } + internal static void LogDebug(ILogger logger, string location, string data) + { + if (logger == null) + { + Debug.WriteLine(data); + } + else + { + logger.LogDebug(location + "; " + data); + } + } + internal static void LogDebug(ILogger logger, string location, Exception exception) { if (logger == null) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs similarity index 95% rename from src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index f88b4f1ff3..9ba76753ba 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -11,13 +11,12 @@ using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.Net.Http.Server; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { internal class MessagePump : IServer { - private readonly Microsoft.Net.Http.Server.WebListener _listener; + private readonly WebListener _listener; private readonly ILogger _logger; private IHttpApplication _application; @@ -44,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.WebListener } var optionsInstance = options.Value; - _listener = new Microsoft.Net.Http.Server.WebListener(optionsInstance.ListenerSettings); + _listener = new WebListener(optionsInstance.ListenerSettings); _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); Features = new FeatureCollection(); _serverAddresses = new ServerAddressesFeature(); @@ -56,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.WebListener _shutdownSignal = new ManualResetEvent(false); } - internal Microsoft.Net.Http.Server.WebListener Listener + internal WebListener Listener { get { return _listener; } } @@ -207,7 +206,7 @@ namespace Microsoft.AspNetCore.Server.WebListener context.Dispose(); } - private void ParseAddresses(ICollection addresses, Microsoft.Net.Http.Server.WebListener listener) + private void ParseAddresses(ICollection addresses, WebListener listener) { foreach (var value in addresses) { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.xproj similarity index 90% rename from src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj rename to src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.xproj index aaf4cfb96b..603e49e271 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Microsoft.AspNetCore.Server.WebListener.xproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.xproj @@ -13,5 +13,8 @@ 2.0 + + + \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs index d2ebe14509..a9938a3a70 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/AddressFamily.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { #if NET451 /// diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs similarity index 93% rename from src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs index 61e02d91c9..8168e2c73d 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs @@ -4,7 +4,7 @@ using System; using Microsoft.Extensions.Internal; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class ComNetOS { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ContextAttribute.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ContextAttribute.cs index 5c1dfed25d..6b2449091b 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ContextAttribute.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ContextAttribute.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal enum ContextAttribute { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs similarity index 97% rename from src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs index f72682869c..a444c48854 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.InteropServices; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // Note this type should only be used while the request buffer remains pinned internal class CookedUrl diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs index 56bbb02a4b..80ecc22853 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/DisconnectListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs @@ -8,7 +8,7 @@ using System.Diagnostics; using System.Threading; using Microsoft.Extensions.Logging; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal class DisconnectListener { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs similarity index 94% rename from src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs index 100ee4333e..289252e7dc 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HeapAllocHandle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs @@ -4,7 +4,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal sealed class HeapAllocHandle : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs index 6ba4851852..71b8bfe746 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.Extensions.Primitives; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static unsafe class HttpApi { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs similarity index 93% rename from src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs index 41c21ec4d6..46c725b193 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpRequestQueueV2Handle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs @@ -3,7 +3,7 @@ using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // This class is a wrapper for Http.sys V2 request queue handle. internal sealed class HttpRequestQueueV2Handle : SafeHandleZeroOrMinusOneIsInvalid diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs similarity index 96% rename from src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs index 346351e1a5..4ed550c1d6 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpServerSessionHandle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs @@ -5,7 +5,7 @@ using System; using System.Threading; using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal sealed class HttpServerSessionHandle : CriticalHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs index 58fadd7aff..bf8cda9c6f 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysRequestHeader.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal enum HttpSysRequestHeader { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs similarity index 97% rename from src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs index 4e2fd9f0e4..2d6ee2a915 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysResponseHeader.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal enum HttpSysResponseHeader { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs index dc2138a256..704803bf88 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs @@ -10,7 +10,7 @@ using System.Security; using Microsoft.Win32; #endif -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class HttpSysSettings { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/IntPtrHelper.cs similarity index 91% rename from src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/IntPtrHelper.cs index f4bbeb7e4e..f2cce9fff4 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/IntPtrHelper.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/IntPtrHelper.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class IntPtrHelper { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs similarity index 91% rename from src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs index 16fc5ec4c0..3230b11dda 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class NclUtilities { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs index e8cfff4e5f..a25fb7fc14 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/RequestQueue.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; using System.Threading; using Microsoft.Extensions.Logging; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal class RequestQueue { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SSPIHandle.cs similarity index 94% rename from src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SSPIHandle.cs index 33885c2758..8a6801a3b6 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SSPIHandle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SSPIHandle.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.InteropServices; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct SSPIHandle diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLoadLibrary.cs similarity index 96% rename from src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLoadLibrary.cs index be7547dc1f..c880a7f005 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLoadLibrary.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLoadLibrary.cs @@ -3,7 +3,7 @@ using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFree.cs similarity index 96% rename from src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFree.cs index eed7b8498a..06824eb438 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFree.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFree.cs @@ -4,7 +4,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs similarity index 96% rename from src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs index f2e685f9e3..eb3ecf7487 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalFreeChannelBinding.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -4,7 +4,7 @@ using System; using System.Security.Authentication.ExtendedProtection; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal class SafeLocalFreeChannelBinding : ChannelBinding { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs similarity index 94% rename from src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs index e367283c19..5e60f6e2d1 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeLocalMemHandle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs @@ -4,7 +4,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs similarity index 97% rename from src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs index 70f83b09ea..8073499996 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SafeNativeOverlapped.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.InteropServices; using System.Threading; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal class SafeNativeOverlapped : SafeHandle { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SchProtocols.cs similarity index 97% rename from src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SchProtocols.cs index 845078ce9d..591d585172 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SchProtocols.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SchProtocols.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { using System; using System.Globalization; diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SecurityStatus.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SecurityStatus.cs index 66302a524b..c46b114d8d 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SecurityStatus.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SecurityStatus.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal enum SecurityStatus { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs similarity index 95% rename from src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs index 4dbbeda4fd..445890459c 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/ServerSession.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs @@ -4,7 +4,7 @@ using System; using System.Diagnostics; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal class ServerSession : IDisposable { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs index 9e49128e11..a06adf2913 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/SocketAddress.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs @@ -8,7 +8,7 @@ using System.Globalization; using System.Net; using System.Text; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // a little perf app measured these times when comparing the internal // buffer implemented as a managed byte[] or unmanaged memory IntPtr diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs similarity index 94% rename from src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs index fc916d7837..4c40acb935 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/TokenBindingUtil.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs @@ -3,10 +3,10 @@ using System; using System.Runtime.InteropServices; -using static Microsoft.Net.Http.Server.HttpApi; -using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods.TokenBinding; +using static Microsoft.AspNetCore.Server.HttpSys.HttpApi; +using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods.TokenBinding; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { /// /// Contains helpers for dealing with TLS token binding. diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs index 38dc533ad2..e8a8daa505 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs @@ -5,7 +5,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static unsafe class UnsafeNclNativeMethods { diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs index 5316efdf75..b60f0328e7 100644 --- a/src/Microsoft.Net.Http.Server/NativeInterop/UrlGroup.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs @@ -5,7 +5,7 @@ using System; using System.Diagnostics; using Microsoft.Extensions.Logging; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal class UrlGroup : IDisposable { diff --git a/src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/DeferredDisposableLifetime.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/Overlapped/DeferredDisposableLifetime.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/DeferredDisposableLifetime.cs diff --git a/src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/IDeferredDisposable.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/Overlapped/IDeferredDisposable.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/IDeferredDisposable.cs diff --git a/src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/PreAllocatedOverlapped.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/Overlapped/PreAllocatedOverlapped.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/PreAllocatedOverlapped.cs diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandle.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandle.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandle.cs diff --git a/src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandleOverlapped.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/Overlapped/ThreadPoolBoundHandleOverlapped.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandleOverlapped.cs diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs similarity index 56% rename from src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs index aff612408a..4fc9a7542d 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs @@ -10,4 +10,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCompany("Microsoft Corporation.")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft ASP.NET Core")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.WebListener.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.HttpSys.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..3360ccd879 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs @@ -0,0 +1,206 @@ +// +namespace Microsoft.AspNetCore.Server.HttpSys +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.AspNetCore.Server.HttpSys.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// The destination array is too small. + /// + internal static string Exception_ArrayTooSmall + { + get { return GetString("Exception_ArrayTooSmall"); } + } + + /// + /// The destination array is too small. + /// + internal static string FormatException_ArrayTooSmall() + { + return GetString("Exception_ArrayTooSmall"); + } + + /// + /// End has already been called. + /// + internal static string Exception_EndCalledMultipleTimes + { + get { return GetString("Exception_EndCalledMultipleTimes"); } + } + + /// + /// End has already been called. + /// + internal static string FormatException_EndCalledMultipleTimes() + { + return GetString("Exception_EndCalledMultipleTimes"); + } + + /// + /// The status code '{0}' is not supported. + /// + internal static string Exception_InvalidStatusCode + { + get { return GetString("Exception_InvalidStatusCode"); } + } + + /// + /// The status code '{0}' is not supported. + /// + internal static string FormatException_InvalidStatusCode(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Exception_InvalidStatusCode"), p0); + } + + /// + /// The stream is not seekable. + /// + internal static string Exception_NoSeek + { + get { return GetString("Exception_NoSeek"); } + } + + /// + /// The stream is not seekable. + /// + internal static string FormatException_NoSeek() + { + return GetString("Exception_NoSeek"); + } + + /// + /// The prefix '{0}' is already registered. + /// + internal static string Exception_PrefixAlreadyRegistered + { + get { return GetString("Exception_PrefixAlreadyRegistered"); } + } + + /// + /// The prefix '{0}' is already registered. + /// + internal static string FormatException_PrefixAlreadyRegistered(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Exception_PrefixAlreadyRegistered"), p0); + } + + /// + /// This stream only supports read operations. + /// + internal static string Exception_ReadOnlyStream + { + get { return GetString("Exception_ReadOnlyStream"); } + } + + /// + /// This stream only supports read operations. + /// + internal static string FormatException_ReadOnlyStream() + { + return GetString("Exception_ReadOnlyStream"); + } + + /// + /// More data written than specified in the Content-Length header. + /// + internal static string Exception_TooMuchWritten + { + get { return GetString("Exception_TooMuchWritten"); } + } + + /// + /// More data written than specified in the Content-Length header. + /// + internal static string FormatException_TooMuchWritten() + { + return GetString("Exception_TooMuchWritten"); + } + + /// + /// Only the http and https schemes are supported. + /// + internal static string Exception_UnsupportedScheme + { + get { return GetString("Exception_UnsupportedScheme"); } + } + + /// + /// Only the http and https schemes are supported. + /// + internal static string FormatException_UnsupportedScheme() + { + return GetString("Exception_UnsupportedScheme"); + } + + /// + /// This stream only supports write operations. + /// + internal static string Exception_WriteOnlyStream + { + get { return GetString("Exception_WriteOnlyStream"); } + } + + /// + /// This stream only supports write operations. + /// + internal static string FormatException_WriteOnlyStream() + { + return GetString("Exception_WriteOnlyStream"); + } + + /// + /// The given IAsyncResult does not match this opperation. + /// + internal static string Exception_WrongIAsyncResult + { + get { return GetString("Exception_WrongIAsyncResult"); } + } + + /// + /// The given IAsyncResult does not match this opperation. + /// + internal static string FormatException_WrongIAsyncResult() + { + return GetString("Exception_WrongIAsyncResult"); + } + + /// + /// An exception occured while running an action registered with {0}. + /// + internal static string Warning_ExceptionInOnResponseCompletedAction + { + get { return GetString("Warning_ExceptionInOnResponseCompletedAction"); } + } + + /// + /// An exception occured while running an action registered with {0}. + /// + internal static string FormatWarning_ExceptionInOnResponseCompletedAction(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Warning_ExceptionInOnResponseCompletedAction"), p0); + } + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + + System.Diagnostics.Debug.Assert(value != null); + + if (formatterNames != null) + { + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + } + + return value; + } + } +} diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/BoundaryType.cs similarity index 91% rename from src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/BoundaryType.cs index 9c7a60ef9a..6e2565b433 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/BoundaryType.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/BoundaryType.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal enum BoundaryType { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs index f80701af0a..0eda1c453f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs @@ -14,7 +14,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // This class is used to load the client certificate on-demand. Because client certs are optional, all // failures are handled internally and reported via ClientCertException or ClientCertError. diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs index efac9db46f..aa1751ed6f 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs @@ -6,7 +6,7 @@ using System.Collections; using System.Collections.Generic; using Microsoft.Extensions.Primitives; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { public class HeaderCollection : IDictionary { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs similarity index 96% rename from src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs index 0fffaf499d..9c22ce1695 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderEncoding.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs @@ -3,7 +3,7 @@ using System.Text; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class HeaderEncoding { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs similarity index 97% rename from src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs index ace6b41c00..8b57bb3a4c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HeaderParser.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.Primitives; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class HeaderParser { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs index cbb15b992f..45ed640625 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpKnownHeaderNames.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class HttpKnownHeaderNames { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpReasonPhrase.cs similarity index 95% rename from src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpReasonPhrase.cs index f80d12c9b2..e8781b689d 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpReasonPhrase.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpReasonPhrase.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class HttpReasonPhrase { @@ -84,11 +84,6 @@ namespace Microsoft.Net.Http.Server } }; - internal static string Get(HttpStatusCode code) - { - return Get((int)code); - } - internal static string Get(int code) { if (code >= 100 && code < 600) diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs index 90274e07bf..9a26984742 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs @@ -9,7 +9,7 @@ using System.Security.Claims; using System.Security.Principal; using Microsoft.Extensions.Primitives; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal unsafe class NativeRequestContext : IDisposable { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs index cbcf912b13..40967efa7c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs @@ -6,7 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // A duplex wrapper around RequestStream and ResponseStream. // TODO: Consider merging RequestStream and ResponseStream instead. diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs index 13e62eb367..7538ba9b2c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RawUrlHelper.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class RawUrlHelper { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index f0a8a26e2b..44e1dbba5e 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -10,7 +10,7 @@ using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { public sealed class Request { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index 7753f79074..49d0fc1551 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -11,7 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { public sealed class RequestContext : IDisposable { @@ -99,8 +99,8 @@ namespace Microsoft.Net.Http.Server } // Set the status code and reason phrase - Response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; - Response.ReasonPhrase = HttpReasonPhrase.Get(HttpStatusCode.SwitchingProtocols); + Response.StatusCode = Constants.Status101SwitchingProtocols; + Response.ReasonPhrase = HttpReasonPhrase.Get(Constants.Status101SwitchingProtocols); Response.SendOpaqueUpgrade(); // TODO: Async Request.SwitchToOpaqueMode(); diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs similarity index 93% rename from src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs index 2989607022..431f23558b 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs @@ -1,25 +1,5 @@ -// Copyright (c) Microsoft Open Technologies, Inc. -// All Rights Reserved -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING -// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF -// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR -// NON-INFRINGEMENT. -// See the Apache 2 License for the specific language governing -// permissions and limitations under the License. - -//----------------------------------------------------------------------- -// -// Copyright (c) Katana Contributors. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // using System; @@ -31,7 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Primitives; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class RequestHeaders @@ -82,7 +62,7 @@ namespace Microsoft.Net.Http.Server private StringValues _Via; private StringValues _Warning; - internal StringValues Accept + internal StringValues Accept { get { @@ -104,7 +84,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues AcceptCharset + internal StringValues AcceptCharset { get { @@ -126,7 +106,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues AcceptEncoding + internal StringValues AcceptEncoding { get { @@ -148,7 +128,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues AcceptLanguage + internal StringValues AcceptLanguage { get { @@ -170,7 +150,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Allow + internal StringValues Allow { get { @@ -192,7 +172,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Authorization + internal StringValues Authorization { get { @@ -214,7 +194,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues CacheControl + internal StringValues CacheControl { get { @@ -236,7 +216,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Connection + internal StringValues Connection { get { @@ -258,7 +238,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues ContentEncoding + internal StringValues ContentEncoding { get { @@ -280,7 +260,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues ContentLanguage + internal StringValues ContentLanguage { get { @@ -302,7 +282,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues ContentLength + internal StringValues ContentLength { get { @@ -324,7 +304,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues ContentLocation + internal StringValues ContentLocation { get { @@ -346,7 +326,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues ContentMd5 + internal StringValues ContentMd5 { get { @@ -368,7 +348,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues ContentRange + internal StringValues ContentRange { get { @@ -390,7 +370,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues ContentType + internal StringValues ContentType { get { @@ -412,7 +392,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Cookie + internal StringValues Cookie { get { @@ -434,7 +414,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Date + internal StringValues Date { get { @@ -456,7 +436,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Expect + internal StringValues Expect { get { @@ -478,7 +458,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Expires + internal StringValues Expires { get { @@ -500,7 +480,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues From + internal StringValues From { get { @@ -522,7 +502,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Host + internal StringValues Host { get { @@ -544,7 +524,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues IfMatch + internal StringValues IfMatch { get { @@ -566,7 +546,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues IfModifiedSince + internal StringValues IfModifiedSince { get { @@ -588,7 +568,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues IfNoneMatch + internal StringValues IfNoneMatch { get { @@ -610,7 +590,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues IfRange + internal StringValues IfRange { get { @@ -632,7 +612,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues IfUnmodifiedSince + internal StringValues IfUnmodifiedSince { get { @@ -654,7 +634,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues KeepAlive + internal StringValues KeepAlive { get { @@ -676,7 +656,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues LastModified + internal StringValues LastModified { get { @@ -698,7 +678,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues MaxForwards + internal StringValues MaxForwards { get { @@ -720,7 +700,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Pragma + internal StringValues Pragma { get { @@ -742,7 +722,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues ProxyAuthorization + internal StringValues ProxyAuthorization { get { @@ -764,7 +744,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Range + internal StringValues Range { get { @@ -786,7 +766,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Referer + internal StringValues Referer { get { @@ -808,7 +788,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Te + internal StringValues Te { get { @@ -830,7 +810,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Trailer + internal StringValues Trailer { get { @@ -852,7 +832,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues TransferEncoding + internal StringValues TransferEncoding { get { @@ -874,7 +854,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Translate + internal StringValues Translate { get { @@ -896,7 +876,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Upgrade + internal StringValues Upgrade { get { @@ -918,7 +898,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues UserAgent + internal StringValues UserAgent { get { @@ -940,7 +920,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Via + internal StringValues Via { get { @@ -962,7 +942,7 @@ namespace Microsoft.Net.Http.Server } } - internal StringValues Warning + internal StringValues Warning { get { @@ -1732,7 +1712,7 @@ namespace Microsoft.Net.Http.Server { case 2: if (_Te.Count > 0 - && string.Equals(key, "Te", StringComparison.Ordinal)) + && string.Equals(key, "Te", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x2u) != 0); Te = StringValues.Empty; @@ -1740,8 +1720,8 @@ namespace Microsoft.Net.Http.Server } break; case 3: - if (_Via.Count > 0 - && string.Equals(key, "Via", StringComparison.Ordinal)) + if (_Via.Count > 0 + && string.Equals(key, "Via", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x80u) != 0); Via = StringValues.Empty; @@ -1749,22 +1729,22 @@ namespace Microsoft.Net.Http.Server } break; case 4: - if (_Date.Count > 0 - && string.Equals(key, "Date", StringComparison.Ordinal)) + if (_Date.Count > 0 + && string.Equals(key, "Date", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10000u) != 0); Date = StringValues.Empty; return wasSet; } if (_From.Count > 0 - && string.Equals(key, "From", StringComparison.Ordinal)) + && string.Equals(key, "From", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80000u) != 0); From = StringValues.Empty; return wasSet; } if (_Host.Count > 0 - && string.Equals(key, "Host", StringComparison.Ordinal)) + && string.Equals(key, "Host", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x100000u) != 0); Host = StringValues.Empty; @@ -1773,14 +1753,14 @@ namespace Microsoft.Net.Http.Server break; case 5: if (_Allow.Count > 0 - && string.Equals(key, "Allow", StringComparison.Ordinal)) + && string.Equals(key, "Allow", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10u) != 0); Allow = StringValues.Empty; return wasSet; } if (_Range.Count > 0 - && string.Equals(key, "Range", StringComparison.Ordinal)) + && string.Equals(key, "Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80000000u) != 0); Range = StringValues.Empty; @@ -1789,28 +1769,28 @@ namespace Microsoft.Net.Http.Server break; case 6: if (_Accept.Count > 0 - && string.Equals(key, "Accept", StringComparison.Ordinal)) + && string.Equals(key, "Accept", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1u) != 0); Accept = StringValues.Empty; return wasSet; } if (_Cookie.Count > 0 - && string.Equals(key, "Cookie", StringComparison.Ordinal)) + && string.Equals(key, "Cookie", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8000u) != 0); Cookie = StringValues.Empty; return wasSet; } if (_Expect.Count > 0 - && string.Equals(key, "Expect", StringComparison.Ordinal)) + && string.Equals(key, "Expect", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20000u) != 0); Expect = StringValues.Empty; return wasSet; } if (_Pragma.Count > 0 - && string.Equals(key, "Pragma", StringComparison.Ordinal)) + && string.Equals(key, "Pragma", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20000000u) != 0); Pragma = StringValues.Empty; @@ -1819,35 +1799,35 @@ namespace Microsoft.Net.Http.Server break; case 7: if (_Expires.Count > 0 - && string.Equals(key, "Expires", StringComparison.Ordinal)) + && string.Equals(key, "Expires", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40000u) != 0); Expires = StringValues.Empty; return wasSet; } if (_Referer.Count > 0 - && string.Equals(key, "Referer", StringComparison.Ordinal)) + && string.Equals(key, "Referer", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x1u) != 0); Referer = StringValues.Empty; return wasSet; } if (_Trailer.Count > 0 - && string.Equals(key, "Trailer", StringComparison.Ordinal)) + && string.Equals(key, "Trailer", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x4u) != 0); Trailer = StringValues.Empty; return wasSet; } if (_Upgrade.Count > 0 - && string.Equals(key, "Upgrade", StringComparison.Ordinal)) + && string.Equals(key, "Upgrade", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x20u) != 0); Upgrade = StringValues.Empty; return wasSet; } if (_Warning.Count > 0 - && string.Equals(key, "Warning", StringComparison.Ordinal)) + && string.Equals(key, "Warning", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x100u) != 0); Warning = StringValues.Empty; @@ -1856,14 +1836,14 @@ namespace Microsoft.Net.Http.Server break; case 8: if (_IfMatch.Count > 0 - && string.Equals(key, "If-Match", StringComparison.Ordinal)) + && string.Equals(key, "If-Match", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x200000u) != 0); IfMatch = StringValues.Empty; return wasSet; } if (_IfRange.Count > 0 - && string.Equals(key, "If-Range", StringComparison.Ordinal)) + && string.Equals(key, "If-Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1000000u) != 0); IfRange = StringValues.Empty; @@ -1872,7 +1852,7 @@ namespace Microsoft.Net.Http.Server break; case 9: if (_Translate.Count > 0 - && string.Equals(key, "Translate", StringComparison.Ordinal)) + && string.Equals(key, "Translate", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x10u) != 0); Translate = StringValues.Empty; @@ -1881,21 +1861,21 @@ namespace Microsoft.Net.Http.Server break; case 10: if (_Connection.Count > 0 - && string.Equals(key, "Connection", StringComparison.Ordinal)) + && string.Equals(key, "Connection", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x80u) != 0); Connection = StringValues.Empty; return wasSet; } if (_KeepAlive.Count > 0 - && string.Equals(key, "Keep-Alive", StringComparison.Ordinal)) + && string.Equals(key, "Keep-Alive", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4000000u) != 0); KeepAlive = StringValues.Empty; return wasSet; } if (_UserAgent.Count > 0 - && string.Equals(key, "User-Agent", StringComparison.Ordinal)) + && string.Equals(key, "User-Agent", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x40u) != 0); UserAgent = StringValues.Empty; @@ -1904,7 +1884,7 @@ namespace Microsoft.Net.Http.Server break; case 11: if (_ContentMd5.Count > 0 - && string.Equals(key, "Content-Md5", StringComparison.Ordinal)) + && string.Equals(key, "Content-Md5", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x1000u) != 0); ContentMd5 = StringValues.Empty; @@ -1913,14 +1893,14 @@ namespace Microsoft.Net.Http.Server break; case 12: if (_ContentType.Count > 0 - && string.Equals(key, "Content-Type", StringComparison.Ordinal)) + && string.Equals(key, "Content-Type", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4000u) != 0); ContentType = StringValues.Empty; return wasSet; } if (_MaxForwards.Count > 0 - && string.Equals(key, "Max-Forwards", StringComparison.Ordinal)) + && string.Equals(key, "Max-Forwards", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x10000000u) != 0); MaxForwards = StringValues.Empty; @@ -1929,35 +1909,35 @@ namespace Microsoft.Net.Http.Server break; case 13: if (_Authorization.Count > 0 - && string.Equals(key, "Authorization", StringComparison.Ordinal)) + && string.Equals(key, "Authorization", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x20u) != 0); Authorization = StringValues.Empty; return wasSet; } if (_CacheControl.Count > 0 - && string.Equals(key, "Cache-Control", StringComparison.Ordinal)) + && string.Equals(key, "Cache-Control", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40u) != 0); CacheControl = StringValues.Empty; return wasSet; } if (_ContentRange.Count > 0 - && string.Equals(key, "Content-Range", StringComparison.Ordinal)) + && string.Equals(key, "Content-Range", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2000u) != 0); ContentRange = StringValues.Empty; return wasSet; } if (_IfNoneMatch.Count > 0 - && string.Equals(key, "If-None-Match", StringComparison.Ordinal)) + && string.Equals(key, "If-None-Match", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x800000u) != 0); IfNoneMatch = StringValues.Empty; return wasSet; } if (_LastModified.Count > 0 - && string.Equals(key, "Last-Modified", StringComparison.Ordinal)) + && string.Equals(key, "Last-Modified", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8000000u) != 0); LastModified = StringValues.Empty; @@ -1966,14 +1946,14 @@ namespace Microsoft.Net.Http.Server break; case 14: if (_AcceptCharset.Count > 0 - && string.Equals(key, "Accept-Charset", StringComparison.Ordinal)) + && string.Equals(key, "Accept-Charset", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2u) != 0); AcceptCharset = StringValues.Empty; return wasSet; } if (_ContentLength.Count > 0 - && string.Equals(key, "Content-Length", StringComparison.Ordinal)) + && string.Equals(key, "Content-Length", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x400u) != 0); ContentLength = StringValues.Empty; @@ -1982,14 +1962,14 @@ namespace Microsoft.Net.Http.Server break; case 15: if (_AcceptEncoding.Count > 0 - && string.Equals(key, "Accept-Encoding", StringComparison.Ordinal)) + && string.Equals(key, "Accept-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x4u) != 0); AcceptEncoding = StringValues.Empty; return wasSet; } if (_AcceptLanguage.Count > 0 - && string.Equals(key, "Accept-Language", StringComparison.Ordinal)) + && string.Equals(key, "Accept-Language", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x8u) != 0); AcceptLanguage = StringValues.Empty; @@ -1998,21 +1978,21 @@ namespace Microsoft.Net.Http.Server break; case 16: if (_ContentEncoding.Count > 0 - && string.Equals(key, "Content-Encoding", StringComparison.Ordinal)) + && string.Equals(key, "Content-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x100u) != 0); ContentEncoding = StringValues.Empty; return wasSet; } if (_ContentLanguage.Count > 0 - && string.Equals(key, "Content-Language", StringComparison.Ordinal)) + && string.Equals(key, "Content-Language", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x200u) != 0); ContentLanguage = StringValues.Empty; return wasSet; } if (_ContentLocation.Count > 0 - && string.Equals(key, "Content-Location", StringComparison.Ordinal)) + && string.Equals(key, "Content-Location", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x800u) != 0); ContentLocation = StringValues.Empty; @@ -2021,14 +2001,14 @@ namespace Microsoft.Net.Http.Server break; case 17: if (_IfModifiedSince.Count > 0 - && string.Equals(key, "If-Modified-Since", StringComparison.Ordinal)) + && string.Equals(key, "If-Modified-Since", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x400000u) != 0); IfModifiedSince = StringValues.Empty; return wasSet; } if (_TransferEncoding.Count > 0 - && string.Equals(key, "Transfer-Encoding", StringComparison.Ordinal)) + && string.Equals(key, "Transfer-Encoding", StringComparison.Ordinal)) { bool wasSet = ((_flag1 & 0x8u) != 0); TransferEncoding = StringValues.Empty; @@ -2037,14 +2017,14 @@ namespace Microsoft.Net.Http.Server break; case 19: if (_IfUnmodifiedSince.Count > 0 - && string.Equals(key, "If-Unmodified-Since", StringComparison.Ordinal)) + && string.Equals(key, "If-Unmodified-Since", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x2000000u) != 0); IfUnmodifiedSince = StringValues.Empty; return wasSet; } if (_ProxyAuthorization.Count > 0 - && string.Equals(key, "Proxy-Authorization", StringComparison.Ordinal)) + && string.Equals(key, "Proxy-Authorization", StringComparison.Ordinal)) { bool wasSet = ((_flag0 & 0x40000000u) != 0); ProxyAuthorization = StringValues.Empty; diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.tt similarity index 95% rename from src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.tt index e89825808b..1b4b3a177a 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.Generated.tt +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.tt @@ -54,11 +54,8 @@ Func IsRead = Index => "((_flag" + (Index / 32) + " & 0x" + (1<<(Ind Func MarkRead = Index => "_flag" + (Index / 32) + " |= 0x" + (1<<(Index % 32)).ToString("x") + "u"; Func Clear = Index => "_flag" + (Index / 32) + " &= ~0x" + (1<<(Index % 32)).ToString("x") + "u"; #> -//----------------------------------------------------------------------- -// -// Copyright (c) Katana Contributors. All rights reserved. -// -//----------------------------------------------------------------------- +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // using System; @@ -70,7 +67,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Primitives; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class RequestHeaders @@ -141,7 +138,7 @@ namespace Microsoft.Net.Http.Server break; <# } #> } - value = null; + value = StringValues.Empty; return false; } @@ -173,10 +170,10 @@ namespace Microsoft.Net.Http.Server case <#=length.Key#>: <# foreach(var prop in length) { #> if (_<#=prop.Name#>.Count > 0 - && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) + && string.Equals(key, "<#=prop.Key#>", StringComparison.Ordinal)) { bool wasSet = <#=IsRead(prop.Index)#>; - <#=prop.Name#> = null; + <#=prop.Name#> = StringValues.Empty; return wasSet; } <# } #> diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs index ece5ef4b39..3d6f701b61 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading; using Microsoft.Extensions.Primitives; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal partial class RequestHeaders : IDictionary { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index 4f3ab879ca..2c0acd8442 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal class RequestStream : Stream { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs index c04376d4ee..c0dd392ace 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs @@ -8,7 +8,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal unsafe class RequestStreamAsyncResult : IAsyncResult, IDisposable { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs index 5129e4e4bb..813970025e 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestUriBuilder.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs @@ -4,7 +4,7 @@ using System; using System.Text; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // We don't use the cooked URL because http.sys unescapes all percent-encoded values. However, // we also can't just use the raw Uri, since http.sys supports not only UTF-8, but also ANSI/DBCS and diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index 7185d039ff..400d755d07 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -9,16 +9,17 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; +using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { public sealed class Response { private ResponseState _responseState; private string _reasonPhrase; - private ResponseStream _nativeStream; + private ResponseBody _nativeStream; private AuthenticationSchemes _authChallenges; private TimeSpan? _cacheTtl; private long _expectedBodyLength; @@ -37,7 +38,7 @@ namespace Microsoft.Net.Http.Server Headers.Clear(); _reasonPhrase = null; _boundaryType = BoundaryType.None; - _nativeResponse.Response_V1.StatusCode = (ushort)HttpStatusCode.OK; + _nativeResponse.Response_V1.StatusCode = (ushort)StatusCodes.Status200OK; _nativeResponse.Response_V1.Version.MajorVersion = 1; _nativeResponse.Response_V1.Version.MinorVersion = 1; _responseState = ResponseState.Created; @@ -274,7 +275,7 @@ namespace Microsoft.Net.Http.Server { if (_nativeStream == null) { - _nativeStream = new ResponseStream(RequestContext); + _nativeStream = new ResponseBody(RequestContext); } } @@ -391,8 +392,7 @@ namespace Microsoft.Net.Http.Server internal HttpApi.HTTP_FLAGS ComputeHeaders(long writeCount, bool endOfRequest = false) { - // 401 - if (StatusCode == (ushort)HttpStatusCode.Unauthorized) + if (StatusCode == (ushort)StatusCodes.Status401Unauthorized) { RequestContext.Server.Settings.Authentication.SetAuthenticationChallenge(RequestContext); } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs index 7a3625efd6..e03a4c0705 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs @@ -10,11 +10,11 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; +using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { - internal class ResponseStream : Stream + internal class ResponseBody : Stream { private RequestContext _requestContext; private long _leftToWrite = long.MinValue; @@ -24,7 +24,7 @@ namespace Microsoft.Net.Http.Server // The last write needs special handling to cancel. private ResponseStreamAsyncResult _lastWrite; - internal ResponseStream(RequestContext requestContext) + internal ResponseBody(RequestContext requestContext) { _requestContext = requestContext; } diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs similarity index 96% rename from src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs index e710e05660..8cd3f1437c 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs @@ -7,9 +7,9 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods; +using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal unsafe class ResponseStreamAsyncResult : IAsyncResult, IDisposable { @@ -18,13 +18,13 @@ namespace Microsoft.Net.Http.Server private SafeNativeOverlapped _overlapped; private HttpApi.HTTP_DATA_CHUNK[] _dataChunks; private FileStream _fileStream; - private ResponseStream _responseStream; + private ResponseBody _responseStream; private TaskCompletionSource _tcs; private uint _bytesSent; private CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationRegistration; - internal ResponseStreamAsyncResult(ResponseStream responseStream, CancellationToken cancellationToken) + internal ResponseStreamAsyncResult(ResponseBody responseStream, CancellationToken cancellationToken) { _responseStream = responseStream; _tcs = new TaskCompletionSource(); @@ -38,7 +38,7 @@ namespace Microsoft.Net.Http.Server _cancellationRegistration = cancellationRegistration; } - internal ResponseStreamAsyncResult(ResponseStream responseStream, ArraySegment data, bool chunked, + internal ResponseStreamAsyncResult(ResponseBody responseStream, ArraySegment data, bool chunked, CancellationToken cancellationToken) : this(responseStream, cancellationToken) { @@ -94,7 +94,7 @@ namespace Microsoft.Net.Http.Server } } - internal ResponseStreamAsyncResult(ResponseStream responseStream, FileStream fileStream, long offset, + internal ResponseStreamAsyncResult(ResponseBody responseStream, FileStream fileStream, long offset, long count, bool chunked, CancellationToken cancellationToken) : this(responseStream, cancellationToken) { diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs similarity index 85% rename from src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs index 792822d3b5..b7c325bc01 100644 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/SslStatus.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal enum SslStatus : byte { diff --git a/src/Microsoft.Net.Http.Server/Resources.resx b/src/Microsoft.AspNetCore.Server.HttpSys/Resources.resx similarity index 100% rename from src/Microsoft.Net.Http.Server/Resources.resx rename to src/Microsoft.AspNetCore.Server.HttpSys/Resources.resx diff --git a/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs similarity index 98% rename from src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs index d042552106..f326853545 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/ResponseStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs @@ -6,7 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { internal class ResponseStream : Stream { @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.WebListener await _onStart(); await _innerStream.WriteAsync(buffer, offset, count, cancellationToken); } -#if NETSTANDARD1_3 +#if NETSTANDARD1_3 public IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) #else public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) diff --git a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs similarity index 97% rename from src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs index ce579ab3bb..0be7301b68 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs @@ -6,9 +6,8 @@ using System.Collections; using System.Collections.Generic; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.Net.Http.Server; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { internal sealed class StandardFeatureCollection : IFeatureCollection { diff --git a/src/Microsoft.Net.Http.Server/TimeoutManager.cs b/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/TimeoutManager.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs index 2daae9ff86..aa61ef85a4 100644 --- a/src/Microsoft.Net.Http.Server/TimeoutManager.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.InteropServices; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { // See the native HTTP_TIMEOUT_LIMIT_INFO structure documentation for additional information. // http://msdn.microsoft.com/en-us/library/aa364661.aspx diff --git a/src/Microsoft.Net.Http.Server/UrlPrefix.cs b/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/UrlPrefix.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs index d63de7c648..1a74402a9f 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefix.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs @@ -4,7 +4,7 @@ using System; using System.Globalization; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { public class UrlPrefix { diff --git a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs index 3c820b73f8..92c50aea09 100644 --- a/src/Microsoft.Net.Http.Server/UrlPrefixCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs @@ -4,7 +4,7 @@ using System.Collections; using System.Collections.Generic; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { /// /// A collection or URL prefixes diff --git a/src/Microsoft.Net.Http.Server/ValidationHelper.cs b/src/Microsoft.AspNetCore.Server.HttpSys/ValidationHelper.cs similarity index 97% rename from src/Microsoft.Net.Http.Server/ValidationHelper.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/ValidationHelper.cs index 0174663b24..7d4c10d7d0 100644 --- a/src/Microsoft.Net.Http.Server/ValidationHelper.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/ValidationHelper.cs @@ -4,7 +4,7 @@ using System; using System.Globalization; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class ValidationHelper { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs similarity index 94% rename from src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs index 62f1a8d376..aac8cec783 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebHostBuilderWebListenerExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs @@ -3,8 +3,8 @@ using System; using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Server.WebListener; -using Microsoft.AspNetCore.Server.WebListener.Internal; +using Microsoft.AspNetCore.Server.HttpSys; +using Microsoft.AspNetCore.Server.HttpSys.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebListener.cs similarity index 97% rename from src/Microsoft.Net.Http.Server/WebListener.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/WebListener.cs index 903103d60e..f10f594d04 100644 --- a/src/Microsoft.Net.Http.Server/WebListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/WebListener.cs @@ -6,9 +6,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { /// /// An HTTP server wrapping the Http.Sys APIs that accepts requests. @@ -301,7 +302,7 @@ namespace Microsoft.Net.Http.Server // Block potential DOS attacks if (requestMemory.UnknownHeaderCount > UnknownHeaderLimit) { - SendError(requestMemory.RequestId, HttpStatusCode.BadRequest, authChallenges: null); + SendError(requestMemory.RequestId, StatusCodes.Status400BadRequest, authChallenges: null); return false; } return true; @@ -311,14 +312,14 @@ namespace Microsoft.Net.Http.Server { if (!Settings.Authentication.AllowAnonymous && !requestMemory.CheckAuthenticated()) { - SendError(requestMemory.RequestId, HttpStatusCode.Unauthorized, + SendError(requestMemory.RequestId, StatusCodes.Status401Unauthorized, AuthenticationManager.GenerateChallenges(Settings.Authentication.Schemes)); return false; } return true; } - private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode, IList authChallenges) + private unsafe void SendError(ulong requestId, int httpStatusCode, IList authChallenges) { HttpApi.HTTP_RESPONSE_V2 httpResponse = new HttpApi.HTTP_RESPONSE_V2(); httpResponse.Response_V1.Version = new HttpApi.HTTP_VERSION(); diff --git a/src/Microsoft.Net.Http.Server/WebListenerException.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerException.cs similarity index 96% rename from src/Microsoft.Net.Http.Server/WebListenerException.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/WebListenerException.cs index 3b3b91d8ac..e96d3ab460 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerException.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerException.cs @@ -6,7 +6,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] public class WebListenerException : Win32Exception diff --git a/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerOptions.cs similarity index 93% rename from src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/WebListenerOptions.cs index ec3b14f2ab..dc2c887ec9 100644 --- a/src/Microsoft.AspNetCore.Server.WebListener/WebListenerOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerOptions.cs @@ -2,9 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.Net.Http.Server; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class WebListenerOptions { diff --git a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerSettings.cs similarity index 98% rename from src/Microsoft.Net.Http.Server/WebListenerSettings.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/WebListenerSettings.cs index cb54783975..c45e5fc759 100644 --- a/src/Microsoft.Net.Http.Server/WebListenerSettings.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerSettings.cs @@ -5,7 +5,7 @@ using System; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { public class WebListenerSettings { diff --git a/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebSocketHelpers.cs similarity index 99% rename from src/Microsoft.Net.Http.Server/WebSocketHelpers.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/WebSocketHelpers.cs index 4338d88f54..48189edf98 100644 --- a/src/Microsoft.Net.Http.Server/WebSocketHelpers.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/WebSocketHelpers.cs @@ -11,7 +11,7 @@ using System.Security.Cryptography; using System.Text; using System.Threading; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class WebSocketHelpers { diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs diff --git a/src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs diff --git a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/CompatHelpers.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/CompatHelpers.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/CompatHelpers.cs diff --git a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/README.md b/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/README.md similarity index 100% rename from src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/README.md rename to src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/README.md diff --git a/src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/SR.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/fx/System/Net/WebSockets/SR.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/SR.cs diff --git a/src/Microsoft.Net.Http.Server/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs diff --git a/src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs similarity index 100% rename from src/Microsoft.Net.Http.Server/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs diff --git a/src/Microsoft.Net.Http.Server/project.json b/src/Microsoft.AspNetCore.Server.HttpSys/project.json similarity index 71% rename from src/Microsoft.Net.Http.Server/project.json rename to src/Microsoft.AspNetCore.Server.HttpSys/project.json index 29f16b72a6..e946fb0992 100644 --- a/src/Microsoft.Net.Http.Server/project.json +++ b/src/Microsoft.AspNetCore.Server.HttpSys/project.json @@ -1,15 +1,19 @@ { "version": "1.2.0-*", - "description": ".NET HTTP server that uses the Windows HTTP Server API.", + "description": "ASP.NET Core HTTP server that uses the Windows HTTP Server API.", "packOptions": { "tags": [ - "netcore", + "aspnetcore", "weblistener" ] }, "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", - "Microsoft.Extensions.Primitives": "1.2.0-*", + "Microsoft.AspNetCore.Hosting": "1.2.0-*", + "Microsoft.Extensions.TaskCache.Sources": { + "version": "1.2.0-*", + "type": "build" + }, + "Microsoft.Net.Http.Headers": "1.2.0-*", "NETStandard.Library": "1.6.2-*" }, "buildOptions": { @@ -22,13 +26,7 @@ "xmlDoc": true }, "frameworks": { - "net451": { - "frameworkAssemblies": { - "System.Runtime": { - "type": "build" - } - } - }, + "net451": {}, "netstandard1.3": { "dependencies": { "Microsoft.Extensions.RuntimeEnvironment.Sources": { diff --git a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs b/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs deleted file mode 100644 index fd8008c8d1..0000000000 --- a/src/Microsoft.AspNetCore.Server.WebListener/Helpers.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Server.WebListener -{ - internal static class Helpers - { - internal static ConfiguredTaskAwaitable SupressContext(this Task task) - { - return task.ConfigureAwait(continueOnCapturedContext: false); - } - - internal static ConfiguredTaskAwaitable SupressContext(this Task task) - { - return task.ConfigureAwait(continueOnCapturedContext: false); - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.WebListener/project.json b/src/Microsoft.AspNetCore.Server.WebListener/project.json deleted file mode 100644 index fbf6de302c..0000000000 --- a/src/Microsoft.AspNetCore.Server.WebListener/project.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core HTTP server for Windows.", - "packOptions": { - "tags": [ - "aspnetcore", - "weblistener" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.Hosting": "1.2.0-*", - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "Microsoft.Net.Http.Headers": "1.2.0-*", - "Microsoft.Net.Http.Server": { - "target": "project" - }, - "NETStandard.Library": "1.6.2-*" - }, - "buildOptions": { - "allowUnsafe": true, - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "frameworks": { - "net451": {}, - "netstandard1.3": { - "dependencies": { - "System.Security.Claims": "4.4.0-*" - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/LogHelper.cs b/src/Microsoft.Net.Http.Server/LogHelper.cs deleted file mode 100644 index bb8ce05414..0000000000 --- a/src/Microsoft.Net.Http.Server/LogHelper.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using Microsoft.Extensions.Logging; - -namespace Microsoft.Net.Http.Server -{ - internal static class LogHelper - { - internal static void LogInfo(ILogger logger, string data) - { - if (logger == null) - { - Debug.WriteLine(data); - } - else - { - logger.LogInformation(data); - } - } - - internal static void LogDebug(ILogger logger, string location, string data) - { - if (logger == null) - { - Debug.WriteLine(data); - } - else - { - logger.LogDebug(location + "; " + data); - } - } - - internal static void LogDebug(ILogger logger, string location, Exception exception) - { - if (logger == null) - { - Debug.WriteLine(exception); - } - else - { - logger.LogDebug(0, exception, location); - } - } - - internal static void LogException(ILogger logger, string location, Exception exception) - { - if (logger == null) - { - Debug.WriteLine(exception); - } - else - { - logger.LogError(0, exception, location); - } - } - - internal static void LogError(ILogger logger, string location, string message) - { - if (logger == null) - { - Debug.WriteLine(message); - } - else - { - logger.LogError(location + "; " + message); - } - } - } -} diff --git a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj b/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj deleted file mode 100644 index 57bd4cadb8..0000000000 --- a/src/Microsoft.Net.Http.Server/Microsoft.Net.Http.Server.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 3f5212aa-e287-49dd-8cec-44bf0a2ac9a1 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs b/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs deleted file mode 100644 index 78c1309651..0000000000 --- a/src/Microsoft.Net.Http.Server/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] \ No newline at end of file diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs deleted file mode 100644 index ae545eec9d..0000000000 --- a/src/Microsoft.Net.Http.Server/RequestProcessing/HttpStatusCode.cs +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.Net.Http.Server -{ - // Redirect Status code numbers that need to be defined. - - /// - /// Contains the values of status - /// codes defined for the HTTP protocol. - /// - // UEUE : Any int can be cast to a HttpStatusCode to allow checking for non http1.1 codes. - internal enum HttpStatusCode - { - // Informational 1xx - - /// - /// [To be supplied.] - /// - Continue = 100, - - /// - /// [To be supplied.] - /// - SwitchingProtocols = 101, - - // Successful 2xx - - /// - /// [To be supplied.] - /// - OK = 200, - - /// - /// [To be supplied.] - /// - Created = 201, - - /// - /// [To be supplied.] - /// - Accepted = 202, - - /// - /// [To be supplied.] - /// - NonAuthoritativeInformation = 203, - - /// - /// [To be supplied.] - /// - NoContent = 204, - - /// - /// [To be supplied.] - /// - ResetContent = 205, - - /// - /// [To be supplied.] - /// - PartialContent = 206, - - // Redirection 3xx - - /// - /// [To be supplied.] - /// - MultipleChoices = 300, - - /// - /// [To be supplied.] - /// - Ambiguous = 300, - - /// - /// [To be supplied.] - /// - MovedPermanently = 301, - - /// - /// [To be supplied.] - /// - Moved = 301, - - /// - /// [To be supplied.] - /// - Found = 302, - - /// - /// [To be supplied.] - /// - Redirect = 302, - - /// - /// [To be supplied.] - /// - SeeOther = 303, - - /// - /// [To be supplied.] - /// - RedirectMethod = 303, - - /// - /// [To be supplied.] - /// - NotModified = 304, - - /// - /// [To be supplied.] - /// - UseProxy = 305, - - /// - /// [To be supplied.] - /// - Unused = 306, - - /// - /// [To be supplied.] - /// - TemporaryRedirect = 307, - - /// - /// [To be supplied.] - /// - RedirectKeepVerb = 307, - - // Client Error 4xx - - /// - /// [To be supplied.] - /// - BadRequest = 400, - - /// - /// [To be supplied.] - /// - Unauthorized = 401, - - /// - /// [To be supplied.] - /// - PaymentRequired = 402, - - /// - /// [To be supplied.] - /// - Forbidden = 403, - - /// - /// [To be supplied.] - /// - NotFound = 404, - - /// - /// [To be supplied.] - /// - MethodNotAllowed = 405, - - /// - /// [To be supplied.] - /// - NotAcceptable = 406, - - /// - /// [To be supplied.] - /// - ProxyAuthenticationRequired = 407, - - /// - /// [To be supplied.] - /// - RequestTimeout = 408, - - /// - /// [To be supplied.] - /// - Conflict = 409, - - /// - /// [To be supplied.] - /// - Gone = 410, - - /// - /// [To be supplied.] - /// - LengthRequired = 411, - - /// - /// [To be supplied.] - /// - PreconditionFailed = 412, - - /// - /// [To be supplied.] - /// - RequestEntityTooLarge = 413, - - /// - /// [To be supplied.] - /// - RequestUriTooLong = 414, - - /// - /// [To be supplied.] - /// - UnsupportedMediaType = 415, - - /// - /// [To be supplied.] - /// - RequestedRangeNotSatisfiable = 416, - - /// - /// [To be supplied.] - /// - ExpectationFailed = 417, - - UpgradeRequired = 426, - - // Server Error 5xx - - /// - /// [To be supplied.] - /// - InternalServerError = 500, - - /// - /// [To be supplied.] - /// - NotImplemented = 501, - - /// - /// [To be supplied.] - /// - BadGateway = 502, - - /// - /// [To be supplied.] - /// - ServiceUnavailable = 503, - - /// - /// [To be supplied.] - /// - GatewayTimeout = 504, - - /// - /// [To be supplied.] - /// - HttpVersionNotSupported = 505, - } // enum HttpStatusCode - - /* - Fielding, et al. Standards Track [Page 3] - - RFC 2616 HTTP/1.1 June 1999 - - - 10.1 Informational 1xx ...........................................57 - 10.1.1 100 Continue .............................................58 - 10.1.2 101 Switching Protocols ..................................58 - 10.2 Successful 2xx ..............................................58 - 10.2.1 200 OK ...................................................58 - 10.2.2 201 Created ..............................................59 - 10.2.3 202 Accepted .............................................59 - 10.2.4 203 Non-Authoritative Information ........................59 - 10.2.5 204 No Content ...........................................60 - 10.2.6 205 Reset Content ........................................60 - 10.2.7 206 Partial Content ......................................60 - 10.3 Redirection 3xx .............................................61 - 10.3.1 300 Multiple Choices .....................................61 - 10.3.2 301 Moved Permanently ....................................62 - 10.3.3 302 Found ................................................62 - 10.3.4 303 See Other ............................................63 - 10.3.5 304 Not Modified .........................................63 - 10.3.6 305 Use Proxy ............................................64 - 10.3.7 306 (Unused) .............................................64 - 10.3.8 307 Temporary Redirect ...................................65 - 10.4 Client Error 4xx ............................................65 - 10.4.1 400 Bad Request .........................................65 - 10.4.2 401 Unauthorized ........................................66 - 10.4.3 402 Payment Required ....................................66 - 10.4.4 403 Forbidden ...........................................66 - 10.4.5 404 Not Found ...........................................66 - 10.4.6 405 Method Not Allowed ..................................66 - 10.4.7 406 Not Acceptable ......................................67 - 10.4.8 407 Proxy Authentication Required .......................67 - 10.4.9 408 Request Timeout .....................................67 - 10.4.10 409 Conflict ............................................67 - 10.4.11 410 Gone ................................................68 - 10.4.12 411 Length Required .....................................68 - 10.4.13 412 Precondition Failed .................................68 - 10.4.14 413 Request Entity Too Large ............................69 - 10.4.15 414 Request-URI Too Long ................................69 - 10.4.16 415 Unsupported Media Type ..............................69 - 10.4.17 416 Requested Range Not Satisfiable .....................69 - 10.4.18 417 Expectation Failed ..................................70 - 10.5 Server Error 5xx ............................................70 - 10.5.1 500 Internal Server Error ................................70 - 10.5.2 501 Not Implemented ......................................70 - 10.5.3 502 Bad Gateway ..........................................70 - 10.5.4 503 Service Unavailable ..................................70 - 10.5.5 504 Gateway Timeout ......................................71 - 10.5.6 505 HTTP Version Not Supported ...........................71 - */ -} // namespace System.Net diff --git a/src/Microsoft.Net.Http.Server/Resources.Designer.cs b/src/Microsoft.Net.Http.Server/Resources.Designer.cs deleted file mode 100644 index 8a3ccb7f45..0000000000 --- a/src/Microsoft.Net.Http.Server/Resources.Designer.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34006 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.Net.Http.Server { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Net.Http.Server.Resources", System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Resources)).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to The destination array is too small.. - /// - internal static string Exception_ArrayTooSmall { - get { - return ResourceManager.GetString("Exception_ArrayTooSmall", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to End has already been called.. - /// - internal static string Exception_EndCalledMultipleTimes { - get { - return ResourceManager.GetString("Exception_EndCalledMultipleTimes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The status code '{0}' is not supported.. - /// - internal static string Exception_InvalidStatusCode { - get { - return ResourceManager.GetString("Exception_InvalidStatusCode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The stream is not seekable.. - /// - internal static string Exception_NoSeek { - get { - return ResourceManager.GetString("Exception_NoSeek", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The prefix '{0}' is already registered.. - /// - internal static string Exception_PrefixAlreadyRegistered { - get { - return ResourceManager.GetString("Exception_PrefixAlreadyRegistered", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This stream only supports read operations.. - /// - internal static string Exception_ReadOnlyStream { - get { - return ResourceManager.GetString("Exception_ReadOnlyStream", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to More data written than specified in the Content-Length header.. - /// - internal static string Exception_TooMuchWritten { - get { - return ResourceManager.GetString("Exception_TooMuchWritten", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Only the http and https schemes are supported.. - /// - internal static string Exception_UnsupportedScheme { - get { - return ResourceManager.GetString("Exception_UnsupportedScheme", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This stream only supports write operations.. - /// - internal static string Exception_WriteOnlyStream { - get { - return ResourceManager.GetString("Exception_WriteOnlyStream", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The given IAsyncResult does not match this opperation.. - /// - internal static string Exception_WrongIAsyncResult { - get { - return ResourceManager.GetString("Exception_WrongIAsyncResult", resourceCulture); - } - } - - /// - /// An exception occured while running an action registered with {0}. - /// - internal static string Warning_ExceptionInOnResponseCompletedAction - { - get { return ResourceManager.GetString("Warning_ExceptionInOnResponseCompletedAction"); } - } - } -} diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index b9dedca1bb..a5ee320541 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -9,9 +9,9 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes; +using AuthenticationSchemes = Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class AuthenticationTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs similarity index 95% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs index d6766522f6..de88885137 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/DummyApplication.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { internal class DummyApplication : IHttpApplication { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs index 2309b9cf7d..6273a8fcdc 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs @@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class HttpsTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs index dc7fb92160..e3b7c9e5a4 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class AuthenticationTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs index da34f91cfe..c65ada8b93 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class HttpsTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs index 6027313f6d..26cc299f09 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class OpaqueUpgradeTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index 6c801f80b7..3fca6084c9 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class RequestBodyTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs index 89457057fe..a333179271 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Primitives; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class RequestHeaderTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs index d907e92e3b..b13ac569dd 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class RequestTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 136883613c..898f3f6fff 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class ResponseBodyTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs index 5494b6a5de..f731bbdd63 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class ResponseCachingTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 69c918b6c9..83e9b126ef 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -12,7 +12,7 @@ using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Primitives; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class ResponseHeaderTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index f5e7128531..6b36ea3241 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class ResponseSendFileTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseTests.cs similarity index 98% rename from test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseTests.cs index cc43f1f356..eacd671453 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseTests.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class ResponseTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs similarity index 99% rename from test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index 3dab88abbb..e6e672bd75 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class ServerTests { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs similarity index 94% rename from test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs index bbe6c7fdbc..7dc43fabcb 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/SkipOffDomainAttribute.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs @@ -4,7 +4,7 @@ using System; using Microsoft.AspNetCore.Testing.xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { /// /// Skips an auth test if the machine is not joined to a Windows domain. diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs similarity index 98% rename from test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs index 65e4ffe3ec..d38768a5cc 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Internal; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { internal static class Utilities { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/WebSocketTests.cs similarity index 98% rename from test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/WebSocketTests.cs index 5aa8990690..cf919cba77 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/WebSocketTests.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys.Listener { [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public class WebSocketTests diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj similarity index 100% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Microsoft.AspNetCore.Server.WebListener.FunctionalTests.xproj rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs index c3db238383..ef2c72e4c1 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs @@ -13,7 +13,7 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class OpaqueUpgradeTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Properties/AssemblyInfo.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs index ebd6b264c6..f2da4d3baf 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class RequestBodyTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs similarity index 98% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs index 196de8dad6..7491df91bd 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Primitives; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class RequestHeaderTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs index 4e75ac0e0a..5327fd3476 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs @@ -14,10 +14,9 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.Net.Http.Server; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class RequestTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs index 6842146dd1..a1bac1ae70 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class ResponseBodyTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs index 0f0c702d25..6a2fe8c57d 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests +namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests { public class ResponseCachingTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index 9b060f2294..cc80f72909 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -13,7 +13,7 @@ using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Primitives; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class ResponseHeaderTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs index 4ee3342188..09fd9c3b86 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class ResponseSendFileTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseTests.cs index 950e80aca3..f2d244edce 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseTests.cs @@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class ResponseTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index d84295a7b3..aa40c90dd8 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -15,10 +15,9 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.Net.Http.Server; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { public class ServerTests { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs similarity index 97% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs index fb6ccbee89..b3c29a620c 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs @@ -7,9 +7,8 @@ using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.Net.Http.Server; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { internal static class Utilities { diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/WebSocketTests.cs similarity index 99% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/WebSocketTests.cs index 5d3c28c736..92baa968ab 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/WebSocketTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/WebSocketTests.cs @@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -namespace Microsoft.AspNetCore.Server.WebListener +namespace Microsoft.AspNetCore.Server.HttpSys { [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public class WebSocketTests diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/project.json similarity index 87% rename from test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json rename to test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/project.json index c2443aa47b..5ff0bc8524 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/project.json @@ -6,7 +6,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Server.WebListener": "1.2.0-*", + "Microsoft.AspNetCore.Server.HttpSys": "1.2.0-*", "Microsoft.AspNetCore.Testing": "1.2.0-*", "xunit": "2.2.0-*" }, @@ -23,6 +23,7 @@ }, "net451": { "frameworkAssemblies": { + "System.DirectoryServices": "", "System.Net.Http": "", "System.Net.Http.WebRequest": "" } diff --git a/test/Microsoft.Net.Http.Server.Tests/Microsoft.Net.Http.Server.Tests.xproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.xproj similarity index 100% rename from test/Microsoft.Net.Http.Server.Tests/Microsoft.Net.Http.Server.Tests.xproj rename to test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.xproj diff --git a/test/Microsoft.Net.Http.Server.Tests/UrlPrefixTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs similarity index 98% rename from test/Microsoft.Net.Http.Server.Tests/UrlPrefixTests.cs rename to test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs index fece76e422..eab6bd24e0 100644 --- a/test/Microsoft.Net.Http.Server.Tests/UrlPrefixTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs @@ -5,7 +5,7 @@ using System; using System.Text; using Xunit; -namespace Microsoft.Net.Http.Server +namespace Microsoft.AspNetCore.Server.HttpSys { public class UrlPrefixTests { diff --git a/test/Microsoft.Net.Http.Server.Tests/project.json b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/project.json similarity index 85% rename from test/Microsoft.Net.Http.Server.Tests/project.json rename to test/Microsoft.AspNetCore.Server.HttpSys.Tests/project.json index 1786eefe1f..fd020492de 100644 --- a/test/Microsoft.Net.Http.Server.Tests/project.json +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/project.json @@ -2,7 +2,7 @@ "testRunner": "xunit", "dependencies": { "dotnet-test-xunit": "2.2.0-*", - "Microsoft.Net.Http.Server": "1.2.0-*", + "Microsoft.AspNetCore.Server.HttpSys": "1.2.0-*", "xunit": "2.2.0-*" }, "frameworks": { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj b/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj deleted file mode 100644 index 3de44fa986..0000000000 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Microsoft.Net.Http.Server.FunctionalTests.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - dcb6e0b1-223d-44e6-8696-4767e5b6e6a1 - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/Properties/AssemblyInfo.cs deleted file mode 100644 index 6d9ec40e96..0000000000 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Testing.xunit; - -[assembly: OSSkipCondition(OperatingSystems.MacOSX)] -[assembly: OSSkipCondition(OperatingSystems.Linux)] \ No newline at end of file diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json b/test/Microsoft.Net.Http.Server.FunctionalTests/project.json deleted file mode 100644 index f245f631b6..0000000000 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/project.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "testRunner": "xunit", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Testing": "1.2.0-*", - "Microsoft.Net.Http.Server": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.Extensions.RuntimeEnvironment.Sources": { - "type": "build", - "version": "1.2.0-*" - }, - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - }, - "System.Net.Http.WinHttpHandler": "4.4.0-*", - "System.Net.WebSockets.Client": "4.4.0-*" - } - }, - "net451": { - "frameworkAssemblies": { - "System.DirectoryServices": "", - "System.Net.Http": "", - "System.Net.Http.WebRequest": "" - } - } - } -} \ No newline at end of file From d7ce8d8103efb546631755dacc6fe38e9d1bea12 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 15 Dec 2016 14:38:59 -0800 Subject: [PATCH 439/597] #283 Update naming, merge options --- samples/HotAddSample/Startup.cs | 10 ++-- samples/SelfHostServer/Startup.cs | 12 ++--- .../AsyncAcceptContext.cs | 14 +++--- ...stenerException.cs => HttpSysException.cs} | 8 ++-- .../{WebListener.cs => HttpSysListener.cs} | 46 +++++++++---------- ...bListenerSettings.cs => HttpSysOptions.cs} | 28 +++++------ .../Internal/WebListenerOptionsSetup.cs | 23 ---------- .../MessagePump.cs | 14 +++--- .../NativeInterop/DisconnectListener.cs | 2 +- .../NativeInterop/RequestQueue.cs | 8 ++-- .../NativeInterop/ServerSession.cs | 2 +- .../NativeInterop/UrlGroup.cs | 8 ++-- .../RequestProcessing/ClientCertLoader.cs | 10 ++-- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestContext.cs | 4 +- .../RequestProcessing/RequestStream.cs | 10 ++-- .../RequestStreamAsyncResult.cs | 2 +- .../RequestProcessing/Response.cs | 8 ++-- .../RequestProcessing/ResponseBody.cs | 12 ++--- .../ResponseStreamAsyncResult.cs | 2 +- .../WebHostBuilderWebListenerExtensions.cs | 17 +++---- .../WebListenerOptions.cs | 29 ------------ .../project.json | 3 +- .../Listener/RequestTests.cs | 5 +- .../Listener/ResponseBodyTests.cs | 12 ++--- .../Listener/ResponseSendFileTests.cs | 8 ++-- .../Listener/ServerTests.cs | 8 ++-- .../Listener/Utilities.cs | 32 ++++++------- .../RequestTests.cs | 4 +- .../ServerTests.cs | 6 +-- .../Utilities.cs | 13 +++--- .../UrlPrefixTests.cs | 2 +- 32 files changed, 152 insertions(+), 212 deletions(-) rename src/Microsoft.AspNetCore.Server.HttpSys/{WebListenerException.cs => HttpSysException.cs} (81%) rename src/Microsoft.AspNetCore.Server.HttpSys/{WebListener.cs => HttpSysListener.cs} (92%) rename src/Microsoft.AspNetCore.Server.HttpSys/{WebListenerSettings.cs => HttpSysOptions.cs} (80%) delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Internal/WebListenerOptionsSetup.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/WebListenerOptions.cs diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index c3a75a32ef..f0ede45da9 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -15,19 +15,19 @@ namespace HotAddSample { public void ConfigureServices(IServiceCollection services) { - services.Configure(options => + services.Configure(options => { - ListenerSettings = options.ListenerSettings; + ServerOptions = options; }); } - public WebListenerSettings ListenerSettings { get; set; } + public HttpSysOptions ServerOptions { get; set; } public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { loggerfactory.AddConsole(LogLevel.Information); - var addresses = ListenerSettings.UrlPrefixes; + var addresses = ServerOptions.UrlPrefixes; addresses.Add("http://localhost:12346/pathBase/"); app.Use(async (context, next) => @@ -102,7 +102,7 @@ namespace HotAddSample { var host = new WebHostBuilder() .UseStartup() - .UseWebListener() + .UseHttpSys() .Build(); host.Run(); diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 9647038bfd..f327d5bb71 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -16,10 +16,10 @@ namespace SelfHostServer public void ConfigureServices(IServiceCollection services) { // Server options can be configured here instead of in Main. - services.Configure(options => + services.Configure(options => { - options.ListenerSettings.Authentication.Schemes = AuthenticationSchemes.None; - options.ListenerSettings.Authentication.AllowAnonymous = true; + options.Authentication.Schemes = AuthenticationSchemes.None; + options.Authentication.AllowAnonymous = true; }); } @@ -49,10 +49,10 @@ namespace SelfHostServer { var host = new WebHostBuilder() .UseStartup() - .UseWebListener(options => + .UseHttpSys(options => { - options.ListenerSettings.Authentication.Schemes = AuthenticationSchemes.None; - options.ListenerSettings.Authentication.AllowAnonymous = true; + options.Authentication.Schemes = AuthenticationSchemes.None; + options.Authentication.AllowAnonymous = true; }) .Build(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs index 5fbd001407..3057e138e7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs @@ -14,10 +14,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(IOWaitCallback); private TaskCompletionSource _tcs; - private WebListener _server; + private HttpSysListener _server; private NativeRequestContext _nativeRequestContext; - internal AsyncAcceptContext(WebListener server) + internal AsyncAcceptContext(HttpSysListener server) { _server = server; _tcs = new TaskCompletionSource(); @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - internal WebListener Server + internal HttpSysListener Server { get { @@ -58,12 +58,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) { - asyncResult.Tcs.TrySetException(new WebListenerException((int)errorCode)); + asyncResult.Tcs.TrySetException(new HttpSysException((int)errorCode)); complete = true; } else { - WebListener server = asyncResult.Server; + HttpSysListener server = asyncResult.Server; if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { // at this point we have received an unmanaged HTTP_REQUEST and memoryBlob @@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { // someother bad error, possible(?) return values are: // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED - asyncResult.Tcs.TrySetException(new WebListenerException((int)statusCode)); + asyncResult.Tcs.TrySetException(new HttpSysException((int)statusCode)); complete = true; } } @@ -169,7 +169,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys retry = true; } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS - && WebListener.SkipIOCPCallbackOnSuccess) + && HttpSysListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. IOCompleted(this, statusCode, bytesTransferred); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerException.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs similarity index 81% rename from src/Microsoft.AspNetCore.Server.HttpSys/WebListenerException.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs index e96d3ab460..7d9b6aa71e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerException.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs @@ -9,19 +9,19 @@ using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Server.HttpSys { [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] - public class WebListenerException : Win32Exception + public class HttpSysException : Win32Exception { - internal WebListenerException() + internal HttpSysException() : base(Marshal.GetLastWin32Error()) { } - internal WebListenerException(int errorCode) + internal HttpSysException(int errorCode) : base(errorCode) { } - internal WebListenerException(int errorCode, string message) + internal HttpSysException(int errorCode, string message) : base(errorCode, message) { } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs similarity index 92% rename from src/Microsoft.AspNetCore.Server.HttpSys/WebListener.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs index f10f594d04..f5efd41533 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/WebListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys /// /// An HTTP server wrapping the Http.Sys APIs that accepts requests. /// - public sealed class WebListener : IDisposable + public sealed class HttpSysListener : IDisposable { // Win8# 559317 fixed a bug in Http.sys's HttpReceiveClientCertificate method. // Without this fix IOCP callbacks were not being called although ERROR_IO_PENDING was @@ -40,16 +40,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys private object _internalLock; - public WebListener() - : this(new WebListenerSettings()) + public HttpSysListener(HttpSysOptions options, ILoggerFactory loggerFactory) { - } - - public WebListener(WebListenerSettings settings) - { - if (settings == null) + if (options == null) { - throw new ArgumentNullException(nameof(settings)); + throw new ArgumentNullException(nameof(options)); + } + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); } if (!HttpApi.Supported) @@ -59,7 +58,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys Debug.Assert(HttpApi.ApiVersion == HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version"); - Settings = settings; + Options = options; + + Logger = LogHelper.CreateLogger(loggerFactory, typeof(HttpSysListener)); _state = State.Stopped; _internalLock = new object(); @@ -99,10 +100,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Disposed, } - internal ILogger Logger - { - get { return Settings.Logger; } - } + internal ILogger Logger { get; private set; } internal UrlGroup UrlGroup { @@ -119,7 +117,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys get { return _disconnectListener; } } - public WebListenerSettings Settings { get; } + public HttpSysOptions Options { get; } public bool IsListening { @@ -148,18 +146,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys return; } - Settings.Authentication.SetUrlGroupSecurity(UrlGroup); - Settings.Timeouts.SetUrlGroupTimeouts(UrlGroup); - Settings.SetRequestQueueLimit(RequestQueue); + Options.Authentication.SetUrlGroupSecurity(UrlGroup); + Options.Timeouts.SetUrlGroupTimeouts(UrlGroup); + Options.SetRequestQueueLimit(RequestQueue); _requestQueue.AttachToUrlGroup(); // All resources are set up correctly. Now add all prefixes. try { - Settings.UrlPrefixes.RegisterAllPrefixes(UrlGroup); + Options.UrlPrefixes.RegisterAllPrefixes(UrlGroup); } - catch (WebListenerException) + catch (HttpSysException) { // If an error occurred while adding prefixes, free all resources allocated by previous steps. _requestQueue.DetachFromUrlGroup(); @@ -191,7 +189,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys return; } - Settings.UrlPrefixes.UnregisterAllPrefixes(); + Options.UrlPrefixes.UnregisterAllPrefixes(); _state = State.Stopped; @@ -285,7 +283,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys // some other bad error, possible(?) return values are: // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED asyncResult.Dispose(); - throw new WebListenerException((int)statusCode); + throw new HttpSysException((int)statusCode); } } catch (Exception exception) @@ -310,10 +308,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal unsafe bool ValidateAuth(NativeRequestContext requestMemory) { - if (!Settings.Authentication.AllowAnonymous && !requestMemory.CheckAuthenticated()) + if (!Options.Authentication.AllowAnonymous && !requestMemory.CheckAuthenticated()) { SendError(requestMemory.RequestId, StatusCodes.Status401Unauthorized, - AuthenticationManager.GenerateChallenges(Settings.Authentication.Schemes)); + AuthenticationManager.GenerateChallenges(Options.Authentication.Schemes)); return false; } return true; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerSettings.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs similarity index 80% rename from src/Microsoft.AspNetCore.Server.HttpSys/WebListenerSettings.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index c45e5fc759..4d8e4ccfaf 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerSettings.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -7,35 +7,31 @@ using Microsoft.Extensions.Logging.Abstractions; namespace Microsoft.AspNetCore.Server.HttpSys { - public class WebListenerSettings + public class HttpSysOptions { private const long DefaultRequestQueueLength = 1000; // Http.sys default. + internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; // The native request queue private long _requestQueueLength = DefaultRequestQueueLength; private RequestQueue _requestQueue; private ILogger _logger = NullLogger.Instance; - public WebListenerSettings() + public HttpSysOptions() { } /// - /// The logger that will be used to create the WebListener instance. This should not be changed - /// after creating the listener. + /// The maximum number of concurrent accepts. /// - public ILogger Logger - { - get { return _logger; } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _logger = value; - } - } + public int MaxAccepts { get; set; } = DefaultMaxAccepts; + + /// + /// Attempts kernel mode caching for responses with eligible headers. The response may not include + /// Set-Cookie, Vary, or Pragma headers. It must include a Cache-Control header with Public and + /// either a Shared-Max-Age or Max-Age value, or an Expires header. + /// + public bool EnableResponseCaching { get; set; } = true; /// /// The url prefixes to register with Http.Sys. These may be modified at any time prior to disposing diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Internal/WebListenerOptionsSetup.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Internal/WebListenerOptionsSetup.cs deleted file mode 100644 index 29aecb6878..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Internal/WebListenerOptionsSetup.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Server.HttpSys.Internal -{ - public class WebListenerOptionsSetup : IConfigureOptions - { - private ILoggerFactory _loggerFactory; - - public WebListenerOptionsSetup(ILoggerFactory loggerFactory) - { - _loggerFactory = loggerFactory; - } - - public void Configure(WebListenerOptions options) - { - options.ListenerSettings.Logger = _loggerFactory.CreateLogger(); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 9ba76753ba..bd6dbecc36 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { internal class MessagePump : IServer { - private readonly WebListener _listener; + private readonly HttpSysListener _listener; private readonly ILogger _logger; private IHttpApplication _application; @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private readonly ServerAddressesFeature _serverAddresses; - public MessagePump(IOptions options, ILoggerFactory loggerFactory) + public MessagePump(IOptions options, ILoggerFactory loggerFactory) { if (options == null) { @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } var optionsInstance = options.Value; - _listener = new WebListener(optionsInstance.ListenerSettings); + _listener = new HttpSysListener(optionsInstance, loggerFactory); _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); Features = new FeatureCollection(); _serverAddresses = new ServerAddressesFeature(); @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _shutdownSignal = new ManualResetEvent(false); } - internal WebListener Listener + internal HttpSysListener Listener { get { return _listener; } } @@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _application = new ApplicationWrapper(application); - if (_listener.Settings.UrlPrefixes.Count == 0) + if (_listener.Options.UrlPrefixes.Count == 0) { throw new InvalidOperationException("No address prefixes were defined."); } @@ -206,11 +206,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys context.Dispose(); } - private void ParseAddresses(ICollection addresses, WebListener listener) + private void ParseAddresses(ICollection addresses, HttpSysListener listener) { foreach (var value in addresses) { - listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(value)); + listener.Options.UrlPrefixes.Add(UrlPrefix.Create(value)); } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs index 80ecc22853..f9a3a7c0e5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs @@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys cts.Cancel(); } - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && HttpSysListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion nativeOverlapped.Dispose(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs index a25fb7fc14..4468f7029e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs @@ -28,17 +28,17 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { - throw new WebListenerException((int)statusCode); + throw new HttpSysException((int)statusCode); } // Disabling callbacks when IO operation completes synchronously (returns ErrorCodes.ERROR_SUCCESS) - if (WebListener.SkipIOCPCallbackOnSuccess && + if (HttpSysListener.SkipIOCPCallbackOnSuccess && !UnsafeNclNativeMethods.SetFileCompletionNotificationModes( requestQueueHandle, UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipCompletionPortOnSuccess | UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipSetEventOnHandle)) { - throw new WebListenerException(Marshal.GetLastWin32Error()); + throw new HttpSysException(Marshal.GetLastWin32Error()); } Handle = requestQueueHandle; @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (result != 0) { - throw new WebListenerException((int)result); + throw new HttpSysException((int)result); } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs index 445890459c..9bebb1e9c5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { - throw new WebListenerException((int)statusCode); + throw new HttpSysException((int)statusCode); } Debug.Assert(serverSessionId != 0, "Invalid id returned by HttpCreateServerSession"); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs index b60f0328e7..2e69c0bcb4 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { - throw new WebListenerException((int)statusCode); + throw new HttpSysException((int)statusCode); } Debug.Assert(urlGroupId != 0, "Invalid id returned by HttpCreateUrlGroup"); @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { - var exception = new WebListenerException((int)statusCode); + var exception = new HttpSysException((int)statusCode); LogHelper.LogException(_logger, "SetUrlGroupProperty", exception); if (throwOnError) { @@ -62,11 +62,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS) { - throw new WebListenerException((int)statusCode, string.Format(Resources.Exception_PrefixAlreadyRegistered, uriPrefix)); + throw new HttpSysException((int)statusCode, string.Format(Resources.Exception_PrefixAlreadyRegistered, uriPrefix)); } else { - throw new WebListenerException((int)statusCode); + throw new HttpSysException((int)statusCode); } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs index 0eda1c453f..b453bed46f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs @@ -187,7 +187,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Complete(0, null); } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - WebListener.SkipIOCPCallbackOnSuccess) + HttpSysListener.SkipIOCPCallbackOnSuccess) { IOCompleted(statusCode, bytesReceived); } @@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys // Some other bad error, possible(?) return values are: // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED // Also ERROR_BAD_DATA if we got it twice or it reported smaller size buffer required. - Fail(new WebListenerException((int)statusCode)); + Fail(new HttpSysException((int)statusCode)); } } while (retry); @@ -254,7 +254,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys asyncResult._overlapped); if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING || - (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && !WebListener.SkipIOCPCallbackOnSuccess)) + (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && !HttpSysListener.SkipIOCPCallbackOnSuccess)) { return; } @@ -267,7 +267,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } else if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { - asyncResult.Fail(new WebListenerException((int)errorCode)); + asyncResult.Fail(new HttpSysException((int)errorCode)); } else { @@ -405,7 +405,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys else { // It's up to the consumer to fail if the missing ChannelBinding matters to them. - LogHelper.LogException(logger, "GetChannelBindingFromTls", new WebListenerException((int)statusCode)); + LogHelper.LogException(logger, "GetChannelBindingFromTls", new HttpSysException((int)statusCode)); break; } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 44e1dbba5e..605e9597f0 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var cookedUrl = nativeRequestContext.GetCookedUrl(); QueryString = cookedUrl.GetQueryString() ?? string.Empty; - var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)nativeRequestContext.UrlContext); + var prefix = requestContext.Server.Options.UrlPrefixes.GetPrefix((int)nativeRequestContext.UrlContext); var rawUrlInBytes = _nativeRequestContext.GetRawUrlInBytes(); var originalPath = RequestUriBuilder.DecodeAndUnescapePath(rawUrlInBytes); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index 49d0fc1551..259b539a61 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private CancellationToken? _disconnectToken; private bool _disposed; - internal RequestContext(WebListener server, NativeRequestContext memoryBlob) + internal RequestContext(HttpSysListener server, NativeRequestContext memoryBlob) { // TODO: Verbose log Server = server; @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Response = new Response(this); } - internal WebListener Server { get; } + internal HttpSysListener Server { get; } internal ILogger Logger => Server.Logger; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index 2c0acd8442..94e7fa7553 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); LogHelper.LogException(Logger, "Read", exception); Abort(); throw exception; @@ -265,14 +265,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys } else { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); LogHelper.LogException(Logger, "BeginRead", exception); Abort(); throw exception; } } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - WebListener.SkipIOCPCallbackOnSuccess) + HttpSysListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode, bytesReturned); @@ -391,14 +391,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys } else { - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); LogHelper.LogException(Logger, "ReadAsync", exception); Abort(); throw exception; } } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - WebListener.SkipIOCPCallbackOnSuccess) + HttpSysListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.Dispose(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs index c0dd392ace..99f04d3fd9 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs @@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - asyncResult.Fail(new IOException(string.Empty, new WebListenerException((int)errorCode))); + asyncResult.Fail(new IOException(string.Empty, new HttpSysException((int)errorCode))); } else { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index 400d755d07..403525f748 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _expectedBodyLength = 0; _nativeStream = null; _cacheTtl = null; - _authChallenges = RequestContext.Server.Settings.Authentication.Schemes; + _authChallenges = RequestContext.Server.Options.Authentication.Schemes; } private enum ResponseState @@ -375,7 +375,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (asyncResult != null && statusCode == ErrorCodes.ERROR_SUCCESS && - WebListener.SkipIOCPCallbackOnSuccess) + HttpSysListener.SkipIOCPCallbackOnSuccess) { asyncResult.BytesSent = bytesSent; // The caller will invoke IOCompleted @@ -394,7 +394,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (StatusCode == (ushort)StatusCodes.Status401Unauthorized) { - RequestContext.Server.Settings.Authentication.SetAuthenticationChallenge(RequestContext); + RequestContext.Server.Options.Authentication.SetAuthenticationChallenge(RequestContext); } var flags = HttpApi.HTTP_FLAGS.NONE; @@ -662,7 +662,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (errorCode != ErrorCodes.ERROR_SUCCESS) { - throw new WebListenerException((int)errorCode); + throw new HttpSysException((int)errorCode); } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs index e03a4c0705..56a104a800 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private ILogger Logger => RequestContext.Server.Logger; - internal bool ThrowWriteExceptions => RequestContext.Server.Settings.ThrowWriteExceptions; + internal bool ThrowWriteExceptions => RequestContext.Server.Options.ThrowWriteExceptions; internal bool IsDisposed => _disposed; @@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (ThrowWriteExceptions) { - var exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + var exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); LogHelper.LogException(Logger, "Flush", exception); Abort(); throw exception; @@ -329,7 +329,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys else if (ThrowWriteExceptions) { asyncResult.Dispose(); - Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); LogHelper.LogException(Logger, "FlushAsync", exception); Abort(); throw exception; @@ -342,7 +342,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - if (statusCode == ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == ErrorCodes.ERROR_SUCCESS && HttpSysListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode, bytesSent); @@ -624,7 +624,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys else if (ThrowWriteExceptions) { asyncResult.Dispose(); - var exception = new IOException(string.Empty, new WebListenerException((int)statusCode)); + var exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); LogHelper.LogException(Logger, "SendFileAsync", exception); Abort(); throw exception; @@ -637,7 +637,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - if (statusCode == ErrorCodes.ERROR_SUCCESS && WebListener.SkipIOCPCallbackOnSuccess) + if (statusCode == ErrorCodes.ERROR_SUCCESS && HttpSysListener.SkipIOCPCallbackOnSuccess) { // IO operation completed synchronously - callback won't be called to signal completion. asyncResult.IOCompleted(statusCode, bytesSent); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs index 8cd3f1437c..28a890e51a 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs @@ -237,7 +237,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } else if (asyncResult._responseStream.ThrowWriteExceptions) { - var exception = new IOException(string.Empty, new WebListenerException((int)errorCode)); + var exception = new IOException(string.Empty, new HttpSysException((int)errorCode)); LogHelper.LogException(logger, "FlushAsync.IOCompleted", exception); asyncResult.Fail(exception); } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs index aac8cec783..ff0d4b5ee9 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs @@ -4,16 +4,14 @@ using System; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Server.HttpSys; -using Microsoft.AspNetCore.Server.HttpSys.Internal; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Hosting { - public static class WebHostBuilderWebListenerExtensions + public static class WebHostBuilderHttpSysExtensions { /// - /// Specify WebListener as the server to be used by the web host. + /// Specify HttpSys as the server to be used by the web host. /// /// /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure. @@ -21,29 +19,28 @@ namespace Microsoft.AspNetCore.Hosting /// /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder. /// - public static IWebHostBuilder UseWebListener(this IWebHostBuilder hostBuilder) + public static IWebHostBuilder UseHttpSys(this IWebHostBuilder hostBuilder) { return hostBuilder.ConfigureServices(services => { - services.AddTransient, WebListenerOptionsSetup>(); services.AddSingleton(); }); } /// - /// Specify WebListener as the server to be used by the web host. + /// Specify HttpSys as the server to be used by the web host. /// /// /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure. /// /// - /// A callback to configure WebListener options. + /// A callback to configure HttpSys options. /// /// /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder. /// - public static IWebHostBuilder UseWebListener(this IWebHostBuilder hostBuilder, Action options) + public static IWebHostBuilder UseHttpSys(this IWebHostBuilder hostBuilder, Action options) { - return hostBuilder.UseWebListener().ConfigureServices(services => + return hostBuilder.UseHttpSys().ConfigureServices(services => { services.Configure(options); }); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerOptions.cs deleted file mode 100644 index dc2c887ec9..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/WebListenerOptions.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - public class WebListenerOptions - { - internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; - - /// - /// Settings for the underlying WebListener instance. - /// - public WebListenerSettings ListenerSettings { get; } = new WebListenerSettings(); - - /// - /// The maximum number of concurrent calls to WebListener.AcceptAsync(). - /// - public int MaxAccepts { get; set; } = DefaultMaxAccepts; - - /// - /// Attempts kernel mode caching for responses with eligible headers. The response may not include - /// Set-Cookie, Vary, or Pragma headers. It must include a Cache-Control header with Public and - /// either a Shared-Max-Age or Max-Age value, or an Expires header. - /// - public bool EnableResponseCaching { get; set; } = true; - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/project.json b/src/Microsoft.AspNetCore.Server.HttpSys/project.json index e946fb0992..e5fc45a8c4 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/project.json +++ b/src/Microsoft.AspNetCore.Server.HttpSys/project.json @@ -4,7 +4,8 @@ "packOptions": { "tags": [ "aspnetcore", - "weblistener" + "weblistener", + "httpsys" ] }, "dependencies": { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs index b13ac569dd..72ba944f74 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs @@ -8,6 +8,7 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.Extensions.Logging; using Xunit; namespace Microsoft.AspNetCore.Server.HttpSys.Listener @@ -147,13 +148,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string root; var server = Utilities.CreateHttpServerReturnRoot("/", out root); server.Dispose(); - server = new WebListener(); + server = new HttpSysListener(new HttpSysOptions(), new LoggerFactory()); using (server) { var uriBuilder = new UriBuilder(root); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - server.Settings.UrlPrefixes.Add(UrlPrefix.Create(uriBuilder.Scheme, uriBuilder.Host, uriBuilder.Port, path)); + server.Options.UrlPrefixes.Add(UrlPrefix.Create(uriBuilder.Scheme, uriBuilder.Host, uriBuilder.Port, path)); } server.Start(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 898f3f6fff..fc281ee6d6 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -272,7 +272,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(Utilities.DefaultTimeout); @@ -331,7 +331,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(Utilities.DefaultTimeout); @@ -374,7 +374,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); @@ -404,7 +404,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); @@ -482,7 +482,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; RequestContext context; using (var client = new HttpClient()) { @@ -516,7 +516,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; RequestContext context; using (var client = new HttpClient()) { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index 6b36ea3241..df3f6ff75d 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -352,7 +352,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(Utilities.DefaultTimeout); @@ -411,7 +411,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(Utilities.DefaultTimeout); @@ -454,7 +454,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); @@ -510,7 +510,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.ThrowWriteExceptions = true; + server.Options.ThrowWriteExceptions = true; RequestContext context; using (var client = new HttpClient()) { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index e6e672bd75..6400b7f202 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -234,7 +234,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { - server.Settings.RequestQueueLimit = 1001; + server.Options.RequestQueueLimit = 1001; var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(Utilities.DefaultTimeout); @@ -262,7 +262,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(string.Empty, response); address += "pathbase/"; - server.Settings.UrlPrefixes.Add(address); + server.Options.UrlPrefixes.Add(address); responseTask = SendRequestAsync(address); @@ -283,7 +283,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener using (var server = Utilities.CreateHttpServer(out address)) { address += "pathbase/"; - server.Settings.UrlPrefixes.Add(address); + server.Options.UrlPrefixes.Add(address); var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(Utilities.DefaultTimeout); @@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var response = await responseTask; Assert.Equal(string.Empty, response); - Assert.True(server.Settings.UrlPrefixes.Remove(address)); + Assert.True(server.Options.UrlPrefixes.Remove(address)); responseTask = SendRequestAsync(address); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs index d38768a5cc..a34cd20945 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs @@ -5,14 +5,14 @@ using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Internal; +using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys.Listener { internal static class Utilities { // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free - // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in - // Microsoft.AspNetCore.Server.WebListener. + // ports during dynamic port allocation. private const int BasePort = 8001; private const int MaxPort = 11000; private static int NextPort = BasePort; @@ -33,27 +33,27 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener #endif } - internal static WebListener CreateHttpAuthServer(AuthenticationSchemes authScheme, bool allowAnonymos, out string baseAddress) + internal static HttpSysListener CreateHttpAuthServer(AuthenticationSchemes authScheme, bool allowAnonymos, out string baseAddress) { var listener = CreateHttpServer(out baseAddress); - listener.Settings.Authentication.Schemes = authScheme; - listener.Settings.Authentication.AllowAnonymous = allowAnonymos; + listener.Options.Authentication.Schemes = authScheme; + listener.Options.Authentication.AllowAnonymous = allowAnonymos; return listener; } - internal static WebListener CreateHttpServer(out string baseAddress) + internal static HttpSysListener CreateHttpServer(out string baseAddress) { string root; return CreateDynamicHttpServer(string.Empty, out root, out baseAddress); } - internal static WebListener CreateHttpServerReturnRoot(string path, out string root) + internal static HttpSysListener CreateHttpServerReturnRoot(string path, out string root) { string baseAddress; return CreateDynamicHttpServer(path, out root, out baseAddress); } - internal static WebListener CreateDynamicHttpServer(string basePath, out string root, out string baseAddress) + internal static HttpSysListener CreateDynamicHttpServer(string basePath, out string root, out string baseAddress) { lock (PortLock) { @@ -63,14 +63,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var prefix = UrlPrefix.Create("http", "localhost", port, basePath); root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; baseAddress = prefix.ToString(); - var listener = new WebListener(); - listener.Settings.UrlPrefixes.Add(prefix); + var listener = new HttpSysListener(new HttpSysOptions(), new LoggerFactory()); + listener.Options.UrlPrefixes.Add(prefix); try { listener.Start(); return listener; } - catch (WebListenerException) + catch (HttpSysException) { listener.Dispose(); } @@ -80,15 +80,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener throw new Exception("Failed to locate a free port."); } - internal static WebListener CreateHttpsServer() + internal static HttpSysListener CreateHttpsServer() { return CreateServer("https", "localhost", 9090, string.Empty); } - internal static WebListener CreateServer(string scheme, string host, int port, string path) + internal static HttpSysListener CreateServer(string scheme, string host, int port, string path) { - WebListener listener = new WebListener(); - listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); + var listener = new HttpSysListener(new HttpSysOptions(), new LoggerFactory()); + listener.Options.UrlPrefixes.Add(UrlPrefix.Create(scheme, host, port, path)); listener.Start(); return listener; } @@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener /// AcceptAsync extension with timeout. This extension should be used in all tests to prevent /// unexpected hangs when a request does not arrive. /// - internal static async Task AcceptAsync(this WebListener server, TimeSpan timeout) + internal static async Task AcceptAsync(this HttpSysListener server, TimeSpan timeout) { var acceptTask = server.AcceptAsync(); var completedTask = await Task.WhenAny(acceptTask, Task.Delay(timeout)); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs index 5327fd3476..bb4688ebf5 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs @@ -305,11 +305,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app); dynamicServer.Dispose(); var rootUri = new Uri(root); - var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); + var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { - server.Listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); + server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); } server.Start(new DummyApplication(app)); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index aa40c90dd8..2794e462ba 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -241,9 +241,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } - var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); - server.Listener.Settings.UrlPrefixes.Add(UrlPrefix.Create(address)); - server.Listener.Settings.RequestQueueLimit = 1001; + var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); + server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address)); + server.Listener.Options.RequestQueueLimit = 1001; using (server) { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs index b3c29a620c..3682e1de5e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs @@ -13,8 +13,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static class Utilities { // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free - // ports during dynamic port allocation. To avoid this, make sure the port range here is different from the range in - // Microsoft.Net.Http.Server. + // ports during dynamic port allocation. private const int BasePort = 5001; private const int MaxPort = 8000; private static int NextPort = BasePort; @@ -50,16 +49,16 @@ namespace Microsoft.AspNetCore.Server.HttpSys root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; baseAddress = prefix.ToString(); - var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); + var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); server.Features.Get().Addresses.Add(baseAddress); - server.Listener.Settings.Authentication.Schemes = authType; - server.Listener.Settings.Authentication.AllowAnonymous = allowAnonymous; + server.Listener.Options.Authentication.Schemes = authType; + server.Listener.Options.Authentication.AllowAnonymous = allowAnonymous; try { server.Start(new DummyApplication(app)); return server; } - catch (WebListenerException) + catch (HttpSysException) { } } @@ -75,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static IServer CreateServer(string scheme, string host, int port, string path, RequestDelegate app) { - var server = new MessagePump(Options.Create(new WebListenerOptions()), new LoggerFactory()); + var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); server.Features.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); server.Start(new DummyApplication(app)); return server; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs index eab6bd24e0..8614ac36db 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData("http://www.example.com:NOTAPORT")] [InlineData("https://www.example.com:NOTAPORT")] [InlineData("http://www.example.com:NOTAPORT/")] - [InlineData("http://foo:/tmp/weblistener-test.sock:5000/doesn't/matter")] + [InlineData("http://foo:/tmp/httpsys-test.sock:5000/doesn't/matter")] public void CreateThrowsForUrlsWithInvalidPorts(string url) { Assert.Throws(() => UrlPrefix.Create(url)); From e524fc2535844f8138d5bd95436973325f7478ac Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 15 Dec 2016 14:54:58 -0800 Subject: [PATCH 440/597] Remove obsolete file --- .../CustomDictionary.xml | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/CustomDictionary.xml diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/CustomDictionary.xml b/src/Microsoft.AspNetCore.Server.HttpSys/CustomDictionary.xml deleted file mode 100644 index 78a76142f7..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/CustomDictionary.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Owin - - - - - From 87e6c4ed3faf28fe51b473cd6032495f1066c451 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 15 Dec 2016 14:55:30 -0800 Subject: [PATCH 441/597] #283 Make old object model internal --- src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs | 2 +- .../RequestProcessing/HeaderCollection.cs | 2 +- .../RequestProcessing/Request.cs | 2 +- .../RequestProcessing/RequestContext.cs | 2 +- .../RequestProcessing/Response.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs index f5efd41533..a42c1f9af4 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys /// /// An HTTP server wrapping the Http.Sys APIs that accepts requests. /// - public sealed class HttpSysListener : IDisposable + internal class HttpSysListener : IDisposable { // Win8# 559317 fixed a bug in Http.sys's HttpReceiveClientCertificate method. // Without this fix IOCP callbacks were not being called although ERROR_IO_PENDING was diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs index aa1751ed6f..4f6cd220e4 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Server.HttpSys { - public class HeaderCollection : IDictionary + internal class HeaderCollection : IDictionary { public HeaderCollection() : this(new Dictionary(4, StringComparer.OrdinalIgnoreCase)) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 605e9597f0..7741232aa6 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; namespace Microsoft.AspNetCore.Server.HttpSys { - public sealed class Request + internal sealed class Request { private NativeRequestContext _nativeRequestContext; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index 259b539a61..6cd4e48d18 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys { - public sealed class RequestContext : IDisposable + internal sealed class RequestContext : IDisposable { private static readonly Action AbortDelegate = Abort; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index 403525f748..9936d817ee 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -15,7 +15,7 @@ using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods; namespace Microsoft.AspNetCore.Server.HttpSys { - public sealed class Response + internal sealed class Response { private ResponseState _responseState; private string _reasonPhrase; From f07e7a5875bdfd2d29c410466720bdb4f0f12522 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 3 Jan 2017 13:54:11 -0800 Subject: [PATCH 442/597] Use the new 101 constant from Http Abstractions. --- src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs | 1 - .../RequestProcessing/RequestContext.cs | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs index f4b0b1884d..83a80676fb 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs @@ -13,7 +13,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal const string Close = "close"; internal const string Zero = "0"; internal const string SchemeDelimiter = "://"; - internal const int Status101SwitchingProtocols = 101; internal static Version V1_0 = new Version(1, 0); internal static Version V1_1 = new Version(1, 1); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index 6cd4e48d18..78f1310f4d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -9,6 +9,7 @@ using System.Security.Authentication.ExtendedProtection; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys @@ -99,8 +100,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } // Set the status code and reason phrase - Response.StatusCode = Constants.Status101SwitchingProtocols; - Response.ReasonPhrase = HttpReasonPhrase.Get(Constants.Status101SwitchingProtocols); + Response.StatusCode = StatusCodes.Status101SwitchingProtocols; + Response.ReasonPhrase = HttpReasonPhrase.Get(StatusCodes.Status101SwitchingProtocols); Response.SendOpaqueUpgrade(); // TODO: Async Request.SwitchToOpaqueMode(); From 6125e3982bb2b4d8cfbbfaaba328a808c8982f32 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 3 Jan 2017 14:08:43 -0800 Subject: [PATCH 443/597] Make last test x-plat conditional --- .../ResponseHeaderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index cc80f72909..3631fc769b 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -255,7 +255,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [Theory, MemberData(nameof(NullHeaderData))] + [ConditionalTheory, MemberData(nameof(NullHeaderData))] public async Task Headers_IgnoreNullHeaders(string headerName, StringValues headerValue, StringValues expectedValue) { string address; From d04dc7182a582e2306b87efdb2fcc5e6b030156d Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 4 Jan 2017 11:13:28 -0800 Subject: [PATCH 444/597] #263 Disable parallel test execution to improve reliability --- .../Properties/AssemblyInfo.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs index 6d9ec40e96..0d585d3063 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Testing.xunit; +using Xunit; [assembly: OSSkipCondition(OperatingSystems.MacOSX)] -[assembly: OSSkipCondition(OperatingSystems.Linux)] \ No newline at end of file +[assembly: OSSkipCondition(OperatingSystems.Linux)] +[assembly: CollectionBehavior(DisableTestParallelization = true)] \ No newline at end of file From 09c993e9a934a8d83e7d6de0f33d187d4080db3a Mon Sep 17 00:00:00 2001 From: Jonathan Channon Date: Thu, 5 Jan 2017 22:02:34 +0000 Subject: [PATCH 445/597] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b1fb2bb26..3f73ae3aaf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -WebListener +HttpSysServer ================= | AppVeyor | Travis | From 691c69f1d2cdfbb401d462d1f0b705d882cac298 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 4 Jan 2017 16:48:23 -0800 Subject: [PATCH 446/597] #283 remove direct WebSocket support --- scripts/UpdateCoreFxCode.ps1 | 44 - .../FeatureContext.cs | 17 - .../RequestProcessing/RequestContext.cs | 150 -- .../WebSocketHelpers.cs | 172 --- .../fx/System/Net/WebSockets/CompatHelpers.cs | 52 - .../fx/System/Net/WebSockets/README.md | 5 - .../fx/System/Net/WebSockets/SR.cs | 27 - .../Net/WebSockets/WebSocketValidate.cs | 132 -- .../System/Net/WebSockets/ManagedWebSocket.cs | 1306 ----------------- .../Listener/WebSocketTests.cs | 108 -- .../WebSocketTests.cs | 182 --- 11 files changed, 2195 deletions(-) delete mode 100644 scripts/UpdateCoreFxCode.ps1 delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/WebSocketHelpers.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/CompatHelpers.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/README.md delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/SR.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs delete mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/WebSocketTests.cs delete mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/WebSocketTests.cs diff --git a/scripts/UpdateCoreFxCode.ps1 b/scripts/UpdateCoreFxCode.ps1 deleted file mode 100644 index 03cd9dfdd5..0000000000 --- a/scripts/UpdateCoreFxCode.ps1 +++ /dev/null @@ -1,44 +0,0 @@ -param([string]$CoreFxRepoRoot) - -$RepoRoot = Split-Path -Parent $PSScriptRoot - -$FilesToCopy = @( - "src\System.Net.WebSockets.Client\src\System\Net\WebSockets\ManagedWebSocket.cs", - "src\Common\src\System\Net\WebSockets\WebSocketValidate.cs" -) - -if(!$CoreFxRepoRoot) { - $CoreFxRepoRoot = "$RepoRoot\..\..\dotnet\corefx" -} - -if(!(Test-Path $CoreFxRepoRoot)) { - throw "Could not find CoreFx repo at $CoreFxRepoRoot" -} -$CoreFxRepoRoot = Convert-Path $CoreFxRepoRoot - -$DestinationRoot = "$RepoRoot\src\Microsoft.Net.Http.Server\fx\" - -$FilesToCopy | foreach { - $Source = Join-Path $CoreFxRepoRoot $_ - $Destination = Join-Path $DestinationRoot $_ - $DestinationDir = Split-Path -Parent $Destination - - if(!(Test-Path $Source)) { - Write-Warning "Can't find source file: $Source" - } else { - if(!(Test-Path $DestinationDir)) { - mkdir $DestinationDir | Out-Null - } - if(Test-Path $Destination) { - del $Destination - } - Write-Host "Copying $_" - - $SourceCode = [IO.File]::ReadAllText($Source) - $SourceCode = $SourceCode.Replace("Task.FromException", "CompatHelpers.FromException") - $SourceCode = $SourceCode.Replace("Task.CompletedTask", "CompatHelpers.CompletedTask") - $SourceCode = $SourceCode.Replace("Array.Empty", "CompatHelpers.Empty") - $SourceCode = $SourceCode.Replace("nameof(ClientWebSocket)", "`"ClientWebSocket`"") - [IO.File]::WriteAllText($Destination, $SourceCode) - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index 867e1e55b3..f63599a01c 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; -using System.Net.WebSockets; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -28,7 +27,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys // ITlsTokenBindingFeature, TODO: https://github.com/aspnet/WebListener/issues/231 IHttpBufferingFeature, IHttpRequestLifetimeFeature, - IHttpWebSocketFeature, IHttpAuthenticationFeature, IHttpUpgradeFeature, IHttpRequestIdentifierFeature @@ -442,21 +440,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys return await _requestContext.UpgradeAsync(); } - bool IHttpWebSocketFeature.IsWebSocketRequest => _requestContext.IsWebSocketRequest; - - async Task IHttpWebSocketFeature.AcceptAsync(WebSocketAcceptContext context) - { - // TODO: Advanced params - string subProtocol = null; - if (context != null) - { - subProtocol = context.SubProtocol; - } - - await OnStart(); - return await _requestContext.AcceptWebSocketAsync(subProtocol); - } - ClaimsPrincipal IHttpAuthenticationFeature.User { get { return _user; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index 78f1310f4d..428bf2a18c 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using System.IO; -using System.Net.WebSockets; using System.Security.Authentication.ExtendedProtection; using System.Security.Claims; using System.Threading; @@ -110,155 +109,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys return Task.FromResult(opaqueStream); } - // Compare ValidateWebSocketRequest - public bool IsWebSocketRequest - { - get - { - if (!WebSocketHelpers.AreWebSocketsSupported) - { - return false; - } - - if (!IsUpgradableRequest) - { - return false; - } - - if (Request.KnownMethod != HttpApi.HTTP_VERB.HttpVerbGET) - { - return false; - } - - // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - var connection = Request.Headers[HttpKnownHeaderNames.Connection].ToString(); - if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) - { - return false; - } - - // Upgrade: websocket - var upgrade = Request.Headers[HttpKnownHeaderNames.Upgrade]; - if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Sec-WebSocket-Version: 13 - var version = Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - if (!string.Equals(WebSocketHelpers.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Sec-WebSocket-Key: {base64string} - var key = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - if (!WebSocketHelpers.IsValidWebSocketKey(key)) - { - return false; - } - - return true; - } - } - - // Compare IsWebSocketRequest() - private void ValidateWebSocketRequest() - { - if (!WebSocketHelpers.AreWebSocketsSupported) - { - throw new NotSupportedException("WebSockets are not supported on this platform."); - } - - if (!IsUpgradableRequest) - { - throw new InvalidOperationException("This request is not a valid upgrade request."); - } - - if (Request.KnownMethod != HttpApi.HTTP_VERB.HttpVerbGET) - { - throw new InvalidOperationException("This request is not a valid upgrade request; invalid verb: " + Request.Method); - } - - // Connection: Upgrade (some odd clients send Upgrade,KeepAlive) - var connection = Request.Headers[HttpKnownHeaderNames.Connection].ToString(); - if (connection == null || connection.IndexOf(HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase) < 0) - { - throw new InvalidOperationException("The Connection header is invalid: " + connection); - } - - // Upgrade: websocket - var upgrade = Request.Headers[HttpKnownHeaderNames.Upgrade]; - if (!string.Equals(WebSocketHelpers.WebSocketUpgradeToken, upgrade, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("The Upgrade header is invalid: " + upgrade); - } - - // Sec-WebSocket-Version: 13 - var version = Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion]; - if (!string.Equals(WebSocketHelpers.SupportedProtocolVersion, version, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("The Sec-WebSocket-Version header is invalid or not supported: " + version); - } - - // Sec-WebSocket-Key: {base64string} - var key = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - if (!WebSocketHelpers.IsValidWebSocketKey(key)) - { - throw new InvalidOperationException("The Sec-WebSocket-Key header is invalid: " + upgrade); - } - } - - public Task AcceptWebSocketAsync() - { - return AcceptWebSocketAsync(null, WebSocketHelpers.DefaultReceiveBufferSize, WebSocketHelpers.DefaultKeepAliveInterval); - } - - public Task AcceptWebSocketAsync(string subProtocol) - { - return AcceptWebSocketAsync(subProtocol, WebSocketHelpers.DefaultReceiveBufferSize, WebSocketHelpers.DefaultKeepAliveInterval); - } - - public Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval) - { - return AcceptWebSocketAsync(subProtocol, WebSocketHelpers.DefaultReceiveBufferSize, keepAliveInterval); - } - - public Task AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval) - { - if (!IsUpgradableRequest) - { - throw new InvalidOperationException("This request cannot be upgraded."); - } - WebSocketHelpers.ValidateOptions(subProtocol, keepAliveInterval); - - return AcceptWebSocketAsyncCore(subProtocol, receiveBufferSize, keepAliveInterval); - } - - private async Task AcceptWebSocketAsyncCore(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval) - { - ValidateWebSocketRequest(); - - var subProtocols = Request.Headers.GetValues(HttpKnownHeaderNames.SecWebSocketProtocol); - var shouldSendSecWebSocketProtocolHeader = WebSocketHelpers.ProcessWebSocketProtocolHeader(subProtocols, subProtocol); - if (shouldSendSecWebSocketProtocolHeader) - { - Response.Headers[HttpKnownHeaderNames.SecWebSocketProtocol] = subProtocol; - } - - // negotiate the websocket key return value - var secWebSocketKey = Request.Headers[HttpKnownHeaderNames.SecWebSocketKey]; - var secWebSocketAccept = WebSocketHelpers.GetSecWebSocketAcceptString(secWebSocketKey); - - Response.Headers.Append(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade); - Response.Headers.Append(HttpKnownHeaderNames.Upgrade, WebSocketHelpers.WebSocketUpgradeToken); - Response.Headers.Append(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept); - - var opaqueStream = await UpgradeAsync(); - - return WebSocketHelpers.CreateServerWebSocket(opaqueStream, subProtocol, receiveBufferSize, keepAliveInterval); - } - // TODO: Public when needed internal bool TryGetChannelBinding(ref ChannelBinding value) { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebSocketHelpers.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebSocketHelpers.cs deleted file mode 100644 index 48189edf98..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/WebSocketHelpers.cs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net.WebSockets; -using System.Security.Cryptography; -using System.Text; -using System.Threading; - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - internal static class WebSocketHelpers - { - internal static string SupportedProtocolVersion = "13"; - - internal const string SecWebSocketKeyGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - internal const string WebSocketUpgradeToken = "websocket"; - internal const int DefaultReceiveBufferSize = 16 * 1024; - internal const int DefaultClientSendBufferSize = 16 * 1024; - internal const int MaxControlFramePayloadLength = 123; - internal static readonly TimeSpan DefaultKeepAliveInterval = TimeSpan.FromMinutes(2); - - // RFC 6455 requests WebSocket clients to let the server initiate the TCP close to avoid that client sockets - // end up in TIME_WAIT-state - // - // After both sending and receiving a Close message, an endpoint considers the WebSocket connection closed and - // MUST close the underlying TCP connection. The server MUST close the underlying TCP connection immediately; - // the client SHOULD wait for the server to close the connection but MAY close the connection at any time after - // sending and receiving a Close message, e.g., if it has not received a TCP Close from the server in a - // reasonable time period. - internal const int ClientTcpCloseTimeout = 1000; // 1s - - private const int CloseStatusCodeAbort = 1006; - private const int CloseStatusCodeFailedTLSHandshake = 1015; - private const int InvalidCloseStatusCodesFrom = 0; - private const int InvalidCloseStatusCodesTo = 999; - private const string Separators = "()<>@,;:\\\"/[]?={} "; - - internal static readonly ArraySegment EmptyPayload = new ArraySegment(new byte[] { }, 0, 0); - private static readonly Random KeyGenerator = new Random(); - - internal static bool AreWebSocketsSupported - { - get - { - return ComNetOS.IsWin8orLater; - } - } - - internal static bool IsValidWebSocketKey(string key) - { - if (string.IsNullOrWhiteSpace(key)) - { - return false; - } - // TODO: - // throw new NotImplementedException(); - return true; - } - - internal static string GetSecWebSocketAcceptString(string secWebSocketKey) - { - string retVal; - // SHA1 used only for hashing purposes, not for crypto. Check here for FIPS compat. - using (SHA1 sha1 = SHA1.Create()) - { - string acceptString = string.Concat(secWebSocketKey, WebSocketHelpers.SecWebSocketKeyGuid); - byte[] toHash = Encoding.UTF8.GetBytes(acceptString); - retVal = Convert.ToBase64String(sha1.ComputeHash(toHash)); - } - return retVal; - } - - internal static WebSocket CreateServerWebSocket(Stream opaqueStream, string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval) - { - return ManagedWebSocket.CreateFromConnectedStream(opaqueStream, isServer: true, subprotocol: subProtocol, - keepAliveIntervalSeconds: (int)keepAliveInterval.TotalSeconds, receiveBufferSize: receiveBufferSize); - } - - // return value here signifies if a Sec-WebSocket-Protocol header should be returned by the server. - internal static bool ProcessWebSocketProtocolHeader(IEnumerable clientSecWebSocketProtocols, string subProtocol) - { - if (clientSecWebSocketProtocols == null || !clientSecWebSocketProtocols.Any()) - { - // client hasn't specified any Sec-WebSocket-Protocol header - if (!string.IsNullOrEmpty(subProtocol)) - { - // If the server specified _anything_ this isn't valid. - throw new WebSocketException(WebSocketError.UnsupportedProtocol, - "The client did not specify a Sec-WebSocket-Protocol header. SubProtocol: " + subProtocol); - } - // Treat empty and null from the server as the same thing here, server should not send headers. - return false; - } - - // here, we know the client specified something and it's non-empty. - - if (string.IsNullOrEmpty(subProtocol)) - { - // client specified some protocols, server specified 'null'. So server should send headers. - return false; - } - - // here, we know that the client has specified something, it's not empty - // and the server has specified exactly one protocol - - // client specified protocols, serverOptions has exactly 1 non-empty entry. Check that - // this exists in the list the client specified. - foreach (var currentRequestProtocol in clientSecWebSocketProtocols) - { - if (string.Compare(subProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase) == 0) - { - return true; - } - } - - throw new WebSocketException(WebSocketError.UnsupportedProtocol, - $"Unsupported protocol: {subProtocol}; Client supported protocols: {string.Join(", ", clientSecWebSocketProtocols)}"); - } - - internal static void ValidateSubprotocol(string subProtocol) - { - if (string.IsNullOrEmpty(subProtocol)) - { - return; - } - - char[] chars = subProtocol.ToCharArray(); - string invalidChar = null; - int i = 0; - while (i < chars.Length) - { - char ch = chars[i]; - if (ch < 0x21 || ch > 0x7e) - { - invalidChar = string.Format(CultureInfo.InvariantCulture, "[{0}]", (int)ch); - break; - } - - if (!char.IsLetterOrDigit(ch) && - Separators.IndexOf(ch) >= 0) - { - invalidChar = ch.ToString(); - break; - } - - i++; - } - - if (invalidChar != null) - { - throw new ArgumentException($"Invalid character '{invalidChar}' in the subProtocol '{subProtocol}'", nameof(subProtocol)); - } - } - - internal static void ValidateOptions(string subProtocol, TimeSpan keepAliveInterval) - { - ValidateSubprotocol(subProtocol); - - // -1 - if (keepAliveInterval < Timeout.InfiniteTimeSpan) - { - throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), keepAliveInterval, - "The value must be greater than or equal too 0 seconds, or -1 second to disable."); - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/CompatHelpers.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/CompatHelpers.cs deleted file mode 100644 index 09b226a964..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/CompatHelpers.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace System.Net.WebSockets -{ - // Needed to support the WebSockets code from CoreFX. - internal static class CompatHelpers - { - internal static readonly Task CompletedTask; - - static CompatHelpers() - { - var tcs = new TaskCompletionSource(); - tcs.SetResult(null); - CompletedTask = tcs.Task; - } - - public static Task FromException(Exception ex) - { -#if NET451 - return FromException(ex); -#else - return Task.FromException(ex); -#endif - } - - public static Task FromException(Exception ex) - { -#if NET451 - var tcs = new TaskCompletionSource(); - tcs.SetException(ex); - return tcs.Task; -#else - return Task.FromException(ex); -#endif - } - - internal static T[] Empty() - { -#if NET451 - return new T[0]; -#else - return Array.Empty(); -#endif - } - } - - // This is just here to be used by a nameof in the CoreFX code. - //internal static class ClientWebSocket { } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/README.md b/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/README.md deleted file mode 100644 index 4b8f84b7ed..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# External Code - -External code copied from CoreFX. Do not modify files in this directory, use the `scripts\UpdateCoreFxCore.ps1` script in the repo root. - -This folder structure is designed to exactly mirror the structure in the CoreFX repo (hence the deep nesting). \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/SR.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/SR.cs deleted file mode 100644 index c7e3a8da7a..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/fx/System/Net/WebSockets/SR.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace System.Net.WebSockets -{ - // Needed to support the WebSockets code from CoreFX. - internal static class SR - { - internal static readonly string net_Websockets_AlreadyOneOutstandingOperation = nameof(net_Websockets_AlreadyOneOutstandingOperation); - internal static readonly string net_WebSockets_Argument_InvalidMessageType = nameof(net_WebSockets_Argument_InvalidMessageType); - internal static readonly string net_WebSockets_InvalidCharInProtocolString = nameof(net_WebSockets_InvalidCharInProtocolString); - internal static readonly string net_WebSockets_InvalidCloseStatusCode = nameof(net_WebSockets_InvalidCloseStatusCode); - internal static readonly string net_WebSockets_InvalidCloseStatusDescription = nameof(net_WebSockets_InvalidCloseStatusDescription); - internal static readonly string net_WebSockets_InvalidEmptySubProtocol = nameof(net_WebSockets_InvalidEmptySubProtocol); - internal static readonly string net_WebSockets_InvalidState = nameof(net_WebSockets_InvalidState); - internal static readonly string net_WebSockets_InvalidState_ClosedOrAborted = nameof(net_WebSockets_InvalidState_ClosedOrAborted); - internal static readonly string net_WebSockets_ReasonNotNull = nameof(net_WebSockets_ReasonNotNull); - internal static readonly string net_WebSockets_UnsupportedPlatform = nameof(net_WebSockets_UnsupportedPlatform); - - internal static string Format(string name, params object[] args) => $"TODO, RESX: {name}; ({string.Join(",", args)})"; - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs deleted file mode 100644 index 06e07f29dd..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/fx/src/Common/src/System/Net/WebSockets/WebSocketValidate.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Globalization; -using System.Text; - -namespace System.Net.WebSockets -{ - internal static class WebSocketValidate - { - internal const int MaxControlFramePayloadLength = 123; - private const int CloseStatusCodeAbort = 1006; - private const int CloseStatusCodeFailedTLSHandshake = 1015; - private const int InvalidCloseStatusCodesFrom = 0; - private const int InvalidCloseStatusCodesTo = 999; - private const string Separators = "()<>@,;:\\\"/[]?={} "; - - internal static void ValidateSubprotocol(string subProtocol) - { - if (string.IsNullOrWhiteSpace(subProtocol)) - { - throw new ArgumentException(SR.net_WebSockets_InvalidEmptySubProtocol, nameof(subProtocol)); - } - - string invalidChar = null; - int i = 0; - while (i < subProtocol.Length) - { - char ch = subProtocol[i]; - if (ch < 0x21 || ch > 0x7e) - { - invalidChar = string.Format(CultureInfo.InvariantCulture, "[{0}]", (int)ch); - break; - } - - if (!char.IsLetterOrDigit(ch) && - Separators.IndexOf(ch) >= 0) - { - invalidChar = ch.ToString(); - break; - } - - i++; - } - - if (invalidChar != null) - { - throw new ArgumentException(SR.Format(SR.net_WebSockets_InvalidCharInProtocolString, subProtocol, invalidChar), nameof(subProtocol)); - } - } - - internal static void ValidateCloseStatus(WebSocketCloseStatus closeStatus, string statusDescription) - { - if (closeStatus == WebSocketCloseStatus.Empty && !string.IsNullOrEmpty(statusDescription)) - { - throw new ArgumentException(SR.Format(SR.net_WebSockets_ReasonNotNull, - statusDescription, - WebSocketCloseStatus.Empty), - nameof(statusDescription)); - } - - int closeStatusCode = (int)closeStatus; - - if ((closeStatusCode >= InvalidCloseStatusCodesFrom && - closeStatusCode <= InvalidCloseStatusCodesTo) || - closeStatusCode == CloseStatusCodeAbort || - closeStatusCode == CloseStatusCodeFailedTLSHandshake) - { - // CloseStatus 1006 means Aborted - this will never appear on the wire and is reflected by calling WebSocket.Abort - throw new ArgumentException(SR.Format(SR.net_WebSockets_InvalidCloseStatusCode, - closeStatusCode), - nameof(closeStatus)); - } - - int length = 0; - if (!string.IsNullOrEmpty(statusDescription)) - { - length = Encoding.UTF8.GetByteCount(statusDescription); - } - - if (length > MaxControlFramePayloadLength) - { - throw new ArgumentException(SR.Format(SR.net_WebSockets_InvalidCloseStatusDescription, - statusDescription, - MaxControlFramePayloadLength), - nameof(statusDescription)); - } - } - - internal static void ThrowPlatformNotSupportedException() - { - throw new PlatformNotSupportedException(SR.net_WebSockets_UnsupportedPlatform); - } - - internal static void ValidateArraySegment(ArraySegment arraySegment, string parameterName) - { - if (arraySegment.Array == null) - { - throw new ArgumentNullException(parameterName + ".Array"); - } - } - - internal static void ThrowIfInvalidState(WebSocketState currentState, bool isDisposed, WebSocketState[] validStates) - { - string validStatesText = string.Empty; - - if (validStates != null && validStates.Length > 0) - { - foreach (WebSocketState validState in validStates) - { - if (currentState == validState) - { - // Ordering is important to maintain .NET 4.5 WebSocket implementation exception behavior. - if (isDisposed) - { - throw new ObjectDisposedException("ClientWebSocket"); - } - - return; - } - } - - validStatesText = string.Join(", ", validStates); - } - - throw new WebSocketException( - WebSocketError.InvalidState, - SR.Format(SR.net_WebSockets_InvalidState, currentState, validStatesText)); - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs deleted file mode 100644 index 8253aebde5..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/fx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ManagedWebSocket.cs +++ /dev/null @@ -1,1306 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -// NOTE: This file is shared between CoreFX and ASP.NET. Be very thoughtful when changing it. - -namespace System.Net.WebSockets -{ - /// A managed implementation of a web socket that sends and receives data via a . - /// - /// Thread-safety: - /// - It's acceptable to call ReceiveAsync and SendAsync in parallel. One of each may run concurrently. - /// - It's acceptable to have a pending ReceiveAsync while CloseOutputAsync or CloseAsync is called. - /// - Attemping to invoke any other operations in parallel may corrupt the instance. Attempting to invoke - /// a send operation while another is in progress or a receive operation while another is in progress will - /// result in an exception. - /// - internal sealed class ManagedWebSocket : WebSocket - { - /// Creates a from a connected to a websocket endpoint. - /// The connected Stream. - /// true if this is the server-side of the connection; false if this is the client-side of the connection. - /// The agreed upon subprotocol for the connection. - /// The interval to use for keep-alive pings. - /// The buffer size to use for received data. - /// The created instance. - public static ManagedWebSocket CreateFromConnectedStream( - Stream stream, bool isServer, string subprotocol, - int keepAliveIntervalSeconds = 30, int receiveBufferSize = 0x1000) - { - return new ManagedWebSocket(stream, isServer, subprotocol, TimeSpan.FromSeconds(keepAliveIntervalSeconds), receiveBufferSize); - } - - /// Per-thread cached 4-byte mask byte array. - [ThreadStatic] - private static byte[] t_headerMask; - - /// Thread-safe random number generator used to generate masks for each send. - private static readonly RandomNumberGenerator s_random = RandomNumberGenerator.Create(); - /// Encoding for the payload of text messages: UTF8 encoding that throws if invalid bytes are discovered, per the RFC. - private static readonly UTF8Encoding s_textEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); - - /// Valid states to be in when calling SendAsync. - private static readonly WebSocketState[] s_validSendStates = { WebSocketState.Open, WebSocketState.CloseReceived }; - /// Valid states to be in when calling ReceiveAsync. - private static readonly WebSocketState[] s_validReceiveStates = { WebSocketState.Open, WebSocketState.CloseSent }; - /// Valid states to be in when calling CloseOutputAsync. - private static readonly WebSocketState[] s_validCloseOutputStates = { WebSocketState.Open, WebSocketState.CloseReceived }; - /// Valid states to be in when calling CloseAsync. - private static readonly WebSocketState[] s_validCloseStates = { WebSocketState.Open, WebSocketState.CloseReceived, WebSocketState.CloseSent }; - - /// The maximum size in bytes of a message frame header that includes mask bytes. - private const int MaxMessageHeaderLength = 14; - /// The maximum size of a control message payload. - private const int MaxControlPayloadLength = 125; - /// Length of the mask XOR'd with the payload data. - private const int MaskLength = 4; - - /// The stream used to communicate with the remote server. - private readonly Stream _stream; - /// - /// true if this is the server-side of the connection; false if it's client. - /// This impacts masking behavior: clients always mask payloads they send and - /// expect to always receive unmasked payloads, whereas servers always send - /// unmasked payloads and expect to always receive masked payloads. - /// - private readonly bool _isServer = false; - /// The agreed upon subprotocol with the server. - private readonly string _subprotocol; - /// Timer used to send periodic pings to the server, at the interval specified - private readonly Timer _keepAliveTimer; - /// CancellationTokenSource used to abort all current and future operations when anything is canceled or any error occurs. - private readonly CancellationTokenSource _abortSource = new CancellationTokenSource(); - /// Buffer used for reading data from the network. - private readonly byte[] _receiveBuffer; - /// - /// Tracks the state of the validity of the UTF8 encoding of text payloads. Text may be split across fragments. - /// - private readonly Utf8MessageState _utf8TextState = new Utf8MessageState(); - /// - /// Semaphore used to ensure that calls to SendFrameAsync don't run concurrently. While - /// is used to fail if a caller tries to issue another SendAsync while a previous one is running, internally - /// we use SendFrameAsync as an implementation detail, and it should not cause user requests to SendAsync to fail, - /// nor should such internal usage be allowed to run concurrently with other internal usage or with SendAsync. - /// - private readonly SemaphoreSlim _sendFrameAsyncLock = new SemaphoreSlim(1, 1); - - // We maintain the current WebSocketState in _state. However, we separately maintain _sentCloseFrame and _receivedCloseFrame - // as there isn't a strict ordering between CloseSent and CloseReceived. If we receive a close frame from the server, we need to - // transition to CloseReceived even if we're currently in CloseSent, and if we send a close frame, we need to transition to - // CloseSent even if we're currently in CloseReceived. - - /// The current state of the web socket in the protocol. - private WebSocketState _state = WebSocketState.Open; - /// true if Dispose has been called; otherwise, false. - private bool _disposed; - /// Whether we've ever sent a close frame. - private bool _sentCloseFrame; - /// Whether we've ever received a close frame. - private bool _receivedCloseFrame; - /// The reason for the close, as sent by the server, or null if not yet closed. - private WebSocketCloseStatus? _closeStatus = null; - /// A description of the close reason as sent by the server, or null if not yet closed. - private string _closeStatusDescription = null; - - /// - /// The last header received in a ReceiveAsync. If ReceiveAsync got a header but then - /// returned fewer bytes than was indicated in the header, subsequent ReceiveAsync calls - /// will use the data from the header to construct the subsequent receive results, and - /// the payload length in this header will be decremented to indicate the number of bytes - /// remaining to be received for that header. As a result, between fragments, the payload - /// length in this header should be 0. - /// - private MessageHeader _lastReceiveHeader = new MessageHeader { Opcode = MessageOpcode.Text, Fin = true }; - /// The offset of the next available byte in the _receiveBuffer. - private int _receiveBufferOffset = 0; - /// The number of bytes available in the _receiveBuffer. - private int _receiveBufferCount = 0; - /// - /// When dealing with partially read fragments of binary/text messages, a mask previously received may still - /// apply, and the first new byte received may not correspond to the 0th position in the mask. This value is - /// the next offset into the mask that should be applied. - /// - private int _receivedMaskOffsetOffset = 0; - /// - /// Buffer used to store the complete message to be sent to the stream. This is needed - /// rather than just sending a header and then the user's buffer, as we need to mutate the - /// buffered data with the mask, and we don't want to change the data in the user's buffer. - /// - private byte[] _sendBuffer; - /// - /// Whether the last SendAsync had endOfMessage==false. We need to track this so that we - /// can send the subsequent message with a continuation opcode if the last message was a fragment. - /// - private bool _lastSendWasFragment; - /// - /// The task returned from the last SendAsync operation to not complete synchronously. - /// If this is not null and not completed when a subsequent SendAsync is issued, an exception occurs. - /// - private Task _lastSendAsync; - /// - /// The task returned from the last ReceiveAsync operation to not complete synchronously. - /// If this is not null and not completed when a subsequent ReceiveAsync is issued, an exception occurs. - /// - private Task _lastReceiveAsync; - - /// Lock used to protect update and check-and-update operations on _state. - private object StateUpdateLock => _abortSource; - /// - /// We need to coordinate between receives and close operations happening concurrently, as a ReceiveAsync may - /// be pending while a Close{Output}Async is issued, which itself needs to loop until a close frame is received. - /// As such, we need thread-safety in the management of . - /// - private object ReceiveAsyncLock => _utf8TextState; // some object, as we're simply lock'ing on it - - /// Initializes the websocket. - /// The connected Stream. - /// true if this is the server-side of the connection; false if this is the client-side of the connection. - /// The agreed upon subprotocol for the connection. - /// The interval to use for keep-alive pings. - /// The buffer size to use for received data. - private ManagedWebSocket(Stream stream, bool isServer, string subprotocol, TimeSpan keepAliveInterval, int receiveBufferSize) - { - Debug.Assert(StateUpdateLock != null, $"Expected {nameof(StateUpdateLock)} to be non-null"); - Debug.Assert(ReceiveAsyncLock != null, $"Expected {nameof(ReceiveAsyncLock)} to be non-null"); - Debug.Assert(StateUpdateLock != ReceiveAsyncLock, "Locks should be different objects"); - - Debug.Assert(stream != null, $"Expected non-null stream"); - Debug.Assert(stream.CanRead, $"Expected readable stream"); - Debug.Assert(stream.CanWrite, $"Expected writeable stream"); - Debug.Assert(keepAliveInterval == Timeout.InfiniteTimeSpan || keepAliveInterval >= TimeSpan.Zero, $"Invalid keepalive interval: {keepAliveInterval}"); - Debug.Assert(receiveBufferSize >= MaxMessageHeaderLength, $"Receive buffer size {receiveBufferSize} is too small"); - - _stream = stream; - _isServer = isServer; - _subprotocol = subprotocol; - _receiveBuffer = new byte[Math.Max(receiveBufferSize, MaxMessageHeaderLength)]; - - // Set up the abort source so that if it's triggered, we transition the instance appropriately. - _abortSource.Token.Register(s => - { - var thisRef = (ManagedWebSocket)s; - - lock (thisRef.StateUpdateLock) - { - WebSocketState state = thisRef._state; - if (state != WebSocketState.Closed && state != WebSocketState.Aborted) - { - thisRef._state = state != WebSocketState.None && state != WebSocketState.Connecting ? - WebSocketState.Aborted : - WebSocketState.Closed; - } - } - }, this); - - // Now that we're opened, initiate the keep alive timer to send periodic pings - if (keepAliveInterval > TimeSpan.Zero) - { - _keepAliveTimer = new Timer(s => ((ManagedWebSocket)s).SendKeepAliveFrameAsync(), this, keepAliveInterval, keepAliveInterval); - } - } - - public override void Dispose() - { - lock (StateUpdateLock) - { - DisposeCore(); - } - } - - private void DisposeCore() - { - Debug.Assert(Monitor.IsEntered(StateUpdateLock), $"Expected {nameof(StateUpdateLock)} to be held"); - if (!_disposed) - { - _disposed = true; - _keepAliveTimer?.Dispose(); - _stream?.Dispose(); - if (_state < WebSocketState.Aborted) - { - _state = WebSocketState.Closed; - } - } - } - - public override WebSocketCloseStatus? CloseStatus => _closeStatus; - - public override string CloseStatusDescription => _closeStatusDescription; - - public override WebSocketState State => _state; - - public override string SubProtocol => _subprotocol; - - public override Task SendAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) - { - if (messageType != WebSocketMessageType.Text && messageType != WebSocketMessageType.Binary) - { - throw new ArgumentException(SR.Format( - SR.net_WebSockets_Argument_InvalidMessageType, - nameof(WebSocketMessageType.Close), nameof(SendAsync), nameof(WebSocketMessageType.Binary), nameof(WebSocketMessageType.Text), nameof(CloseOutputAsync)), - nameof(messageType)); - } - WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer)); - - try - { - WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validSendStates); - ThrowIfOperationInProgress(_lastSendAsync); - } - catch (Exception exc) - { - return CompatHelpers.FromException(exc); - } - - MessageOpcode opcode = - _lastSendWasFragment ? MessageOpcode.Continuation : - messageType == WebSocketMessageType.Binary ? MessageOpcode.Binary : - MessageOpcode.Text; - - Task t = SendFrameAsync(opcode, endOfMessage, buffer, cancellationToken); - _lastSendWasFragment = !endOfMessage; - _lastSendAsync = t; - return t; - } - - public override Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) - { - WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer)); - - try - { - WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validReceiveStates); - - Debug.Assert(!Monitor.IsEntered(StateUpdateLock), $"{nameof(StateUpdateLock)} must never be held when acquiring {nameof(ReceiveAsyncLock)}"); - lock (ReceiveAsyncLock) // synchronize with receives in CloseAsync - { - ThrowIfOperationInProgress(_lastReceiveAsync); - Task t = ReceiveAsyncPrivate(buffer, cancellationToken); - _lastReceiveAsync = t; - return t; - } - } - catch (Exception exc) - { - return CompatHelpers.FromException(exc); - } - } - - public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) - { - WebSocketValidate.ValidateCloseStatus(closeStatus, statusDescription); - - try - { - WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validCloseStates); - } - catch (Exception exc) - { - return CompatHelpers.FromException(exc); - } - - return CloseAsyncPrivate(closeStatus, statusDescription, cancellationToken); - } - - public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) - { - WebSocketValidate.ValidateCloseStatus(closeStatus, statusDescription); - - try - { - WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validCloseOutputStates); - } - catch (Exception exc) - { - return CompatHelpers.FromException(exc); - } - - return SendCloseFrameAsync(closeStatus, statusDescription, cancellationToken); - } - - public override void Abort() - { - _abortSource.Cancel(); - Dispose(); // forcibly tear down connection - } - - /// Sends a websocket frame to the network. - /// The opcode for the message. - /// The value of the FIN bit for the message. - /// The buffer containing the payload data fro the message. - /// The CancellationToken to use to cancel the websocket. - private Task SendFrameAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment payloadBuffer, CancellationToken cancellationToken) - { - // TODO: #4900 SendFrameAsync should in theory typically complete synchronously, making it fast and allocation free. - // However, due to #4900, it almost always yields, resulting in all of the allocations involved in an async method - // yielding, e.g. the boxed state machine, the Action delegate, the MoveNextRunner, and the resulting Task, plus it's - // common that the awaited operation completes so fast after the await that we may end up allocating an AwaitTaskContinuation - // inside of the TaskAwaiter. Since SendFrameAsync is such a core code path, until that can be fixed, we put some - // optimizations in place to avoid a few of those expenses, at the expense of more complicated code; for the common case, - // this code has fewer than half the number and size of allocations. If/when that issue is fixed, this method should be deleted - // and replaced by SendFrameFallbackAsync, which is the same logic but in a much more easily understand flow. - - // If a cancelable cancellation token was provided, that would require registering with it, which means more state we have to - // pass around (the CancellationTokenRegistration), so if it is cancelable, just immediately go to the fallback path. - // Similarly, it should be rare that there are multiple outstanding calls to SendFrameAsync, but if there are, again - // fall back to the fallback path. - return cancellationToken.CanBeCanceled || !_sendFrameAsyncLock.Wait(0) ? - SendFrameFallbackAsync(opcode, endOfMessage, payloadBuffer, cancellationToken) : - SendFrameLockAcquiredNonCancelableAsync(opcode, endOfMessage, payloadBuffer); - } - - /// Sends a websocket frame to the network. The caller must hold the sending lock. - /// The opcode for the message. - /// The value of the FIN bit for the message. - /// The buffer containing the payload data fro the message. - private Task SendFrameLockAcquiredNonCancelableAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment payloadBuffer) - { - Debug.Assert(_sendFrameAsyncLock.CurrentCount == 0, "Caller should hold the _sendFrameAsyncLock"); - - // If we get here, the cancellation token is not cancelable so we don't have to worry about it, - // and we own the semaphore, so we don't need to asynchronously wait for it. - Task writeTask = null; - bool releaseSemaphore = true; - try - { - // Write the payload synchronously to the buffer, then write that buffer out to the network. - int sendBytes = WriteFrameToSendBuffer(opcode, endOfMessage, payloadBuffer); - writeTask = _stream.WriteAsync(_sendBuffer, 0, sendBytes, CancellationToken.None); - - // If the operation happens to complete synchronously (or, more specifically, by - // the time we get from the previous line to here, release the semaphore, propagate - // exceptions, and we're done. - if (writeTask.IsCompleted) - { - writeTask.GetAwaiter().GetResult(); // propagate any exceptions - return CompatHelpers.CompletedTask; - } - - // Up until this point, if an exception occurred (such as when accessing _stream or when - // calling GetResult), we want to release the semaphore. After this point, the semaphore needs - // to remain held until writeTask completes. - releaseSemaphore = false; - } - catch (Exception exc) - { - return CompatHelpers.FromException(_state == WebSocketState.Aborted ? - CreateOperationCanceledException(exc) : - new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc)); - } - finally - { - if (releaseSemaphore) - { - _sendFrameAsyncLock.Release(); - } - } - - // The write was not yet completed. Create and return a continuation that will - // release the semaphore and translate any exception that occurred. - return writeTask.ContinueWith((t, s) => - { - var thisRef = (ManagedWebSocket)s; - thisRef._sendFrameAsyncLock.Release(); - - try { t.GetAwaiter().GetResult(); } - catch (Exception exc) - { - throw thisRef._state == WebSocketState.Aborted ? - CreateOperationCanceledException(exc) : - new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); - } - }, this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); - } - - private async Task SendFrameFallbackAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment payloadBuffer, CancellationToken cancellationToken) - { - await _sendFrameAsyncLock.WaitAsync().ConfigureAwait(false); - try - { - int sendBytes = WriteFrameToSendBuffer(opcode, endOfMessage, payloadBuffer); - using (cancellationToken.Register(s => ((ManagedWebSocket)s).Abort(), this)) - { - await _stream.WriteAsync(_sendBuffer, 0, sendBytes, cancellationToken).ConfigureAwait(false); - } - } - catch (Exception exc) - { - throw _state == WebSocketState.Aborted ? - CreateOperationCanceledException(exc, cancellationToken) : - new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); - } - finally - { - _sendFrameAsyncLock.Release(); - } - } - - /// Writes a frame into the send buffer, which can then be sent over the network. - private int WriteFrameToSendBuffer(MessageOpcode opcode, bool endOfMessage, ArraySegment payloadBuffer) - { - // Grow our send buffer as needed. We reuse the buffer for all messages, with it protected by the send frame lock. - EnsureBufferLength(ref _sendBuffer, payloadBuffer.Count + MaxMessageHeaderLength); - - // Write the message header data to the buffer. - int headerLength; - int? maskOffset = null; - if (_isServer) - { - // The server doesn't send a mask, so the mask offset returned by WriteHeader - // is actually the end of the header. - headerLength = WriteHeader(opcode, _sendBuffer, payloadBuffer, endOfMessage, useMask: false); - } - else - { - // We need to know where the mask starts so that we can use the mask to manipulate the payload data, - // and we need to know the total length for sending it on the wire. - maskOffset = WriteHeader(opcode, _sendBuffer, payloadBuffer, endOfMessage, useMask: true); - headerLength = maskOffset.GetValueOrDefault() + MaskLength; - } - - // Write the payload - if (payloadBuffer.Count > 0) - { - Buffer.BlockCopy(payloadBuffer.Array, payloadBuffer.Offset, _sendBuffer, headerLength, payloadBuffer.Count); - - // If we added a mask to the header, XOR the payload with the mask. We do the manipulation in the send buffer so as to avoid - // changing the data in the caller-supplied payload buffer. - if (maskOffset.HasValue) - { - ApplyMask(_sendBuffer, headerLength, _sendBuffer, maskOffset.Value, 0, payloadBuffer.Count); - } - } - - // Return the number of bytes in the send buffer - return headerLength + payloadBuffer.Count; - } - - private void SendKeepAliveFrameAsync() - { - bool acquiredLock = _sendFrameAsyncLock.Wait(0); - if (acquiredLock) - { - // This exists purely to keep the connection alive; don't wait for the result, and ignore any failures. - // The call will handle releasing the lock. - SendFrameLockAcquiredNonCancelableAsync(MessageOpcode.Ping, true, new ArraySegment(CompatHelpers.Empty())); - } - else - { - // If the lock is already held, something is already getting sent, - // so there's no need to send a keep-alive ping. - } - } - - private static int WriteHeader(MessageOpcode opcode, byte[] sendBuffer, ArraySegment payload, bool endOfMessage, bool useMask) - { - // Client header format: - // 1 bit - FIN - 1 if this is the final fragment in the message (it could be the only fragment), otherwise 0 - // 1 bit - RSV1 - Reserved - 0 - // 1 bit - RSV2 - Reserved - 0 - // 1 bit - RSV3 - Reserved - 0 - // 4 bits - Opcode - How to interpret the payload - // - 0x0 - continuation - // - 0x1 - text - // - 0x2 - binary - // - 0x8 - connection close - // - 0x9 - ping - // - 0xA - pong - // - (0x3 to 0x7, 0xB-0xF - reserved) - // 1 bit - Masked - 1 if the payload is masked, 0 if it's not. Must be 1 for the client - // 7 bits, 7+16 bits, or 7+64 bits - Payload length - // - For length 0 through 125, 7 bits storing the length - // - For lengths 126 through 2^16, 7 bits storing the value 126, followed by 16 bits storing the length - // - For lengths 2^16+1 through 2^64, 7 bits storing the value 127, followed by 64 bytes storing the length - // 0 or 4 bytes - Mask, if Masked is 1 - random value XOR'd with each 4 bytes of the payload, round-robin - // Length bytes - Payload data - - Debug.Assert(sendBuffer.Length >= MaxMessageHeaderLength, $"Expected sendBuffer to be at least {MaxMessageHeaderLength}, got {sendBuffer.Length}"); - - sendBuffer[0] = (byte)opcode; // 4 bits for the opcode - if (endOfMessage) - { - sendBuffer[0] |= 0x80; // 1 bit for FIN - } - - // Store the payload length. - int maskOffset; - if (payload.Count <= 125) - { - sendBuffer[1] = (byte)payload.Count; - maskOffset = 2; // no additional payload length - } - else if (payload.Count <= ushort.MaxValue) - { - sendBuffer[1] = 126; - sendBuffer[2] = (byte)(payload.Count / 256); - sendBuffer[3] = (byte)payload.Count; - maskOffset = 2 + sizeof(ushort); // additional 2 bytes for 16-bit length - } - else - { - sendBuffer[1] = 127; - int length = payload.Count; - for (int i = 9; i >= 2; i--) - { - sendBuffer[i] = (byte)length; - length = length / 256; - } - maskOffset = 2 + sizeof(ulong); // additional 8 bytes for 64-bit length - } - - if (useMask) - { - // Generate the mask. - sendBuffer[1] |= 0x80; - WriteRandomMask(sendBuffer, maskOffset); - } - - // Return the position of the mask. - return maskOffset; - } - - /// Writes a 4-byte random mask to the specified buffer at the specified offset. - /// The buffer to which to write the mask. - /// The offset into the buffer at which to write the mask. - private static void WriteRandomMask(byte[] buffer, int offset) - { - byte[] mask = t_headerMask ?? (t_headerMask = new byte[MaskLength]); - Debug.Assert(mask.Length == MaskLength, $"Expected mask of length {MaskLength}, got {mask.Length}"); - s_random.GetBytes(mask); - Buffer.BlockCopy(mask, 0, buffer, offset, MaskLength); - } - - /// - /// Receive the next text, binary, continuation, or close message, returning information about it and - /// writing its payload into the supplied buffer. Other control messages may be consumed and processed - /// as part of this operation, but data about them will not be returned. - /// - /// The buffer into which payload data should be written. - /// The CancellationToken used to cancel the websocket. - /// Information about the received message. - private async Task ReceiveAsyncPrivate(ArraySegment payloadBuffer, CancellationToken cancellationToken) - { - // This is a long method. While splitting it up into pieces would arguably help with readability, doing so would - // also result in more allocations, as each async method that yields ends up with multiple allocations. The impact - // of those allocations is amortized across all of the awaits in the method, and since we generally expect a receive - // operation to require at most a single yield (while waiting for data to arrive), it's more efficient to have - // everything in the one method. We do separate out pieces for handling close and ping/pong messages, as we expect - // those to be much less frequent (e.g. we should only get one close per websocket), and thus we can afford to pay - // a bit more for readability and maintainability. - - CancellationTokenRegistration registration = cancellationToken.Register(s => ((ManagedWebSocket)s).Abort(), this); - try - { - while (true) // in case we get control frames that should be ignored from the user's perspective - { - // Get the last received header. If its payload length is non-zero, that means we previously - // received the header but were only able to read a part of the fragment, so we should skip - // reading another header and just proceed to use that same header and read more data associated - // with it. If instead its payload length is zero, then we've completed the processing of - // thta message, and we should read the next header. - MessageHeader header = _lastReceiveHeader; - if (header.PayloadLength == 0) - { - if (_receiveBufferCount < (_isServer ? (MaxMessageHeaderLength - MaskLength) : MaxMessageHeaderLength)) - { - // Make sure we have the first two bytes, which includes the start of the payload length. - if (_receiveBufferCount < 2) - { - await EnsureBufferContainsAsync(2, cancellationToken, throwOnPrematureClosure: true).ConfigureAwait(false); - } - - // Then make sure we have the full header based on the payload length. - // If this is the server, we also need room for the received mask. - long payloadLength = _receiveBuffer[_receiveBufferOffset + 1] & 0x7F; - if (_isServer || payloadLength > 125) - { - int minNeeded = - 2 + - (_isServer ? MaskLength : 0) + - (payloadLength <= 125 ? 0 : payloadLength == 126 ? sizeof(ushort) : sizeof(ulong)); // additional 2 or 8 bytes for 16-bit or 64-bit length - await EnsureBufferContainsAsync(minNeeded, cancellationToken).ConfigureAwait(false); - } - } - - if (!TryParseMessageHeaderFromReceiveBuffer(out header)) - { - await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false); - } - _receivedMaskOffsetOffset = 0; - } - - // If the header represents a ping or a pong, it's a control message meant - // to be transparent to the user, so handle it and then loop around to read again. - // Alternatively, if it's a close message, handle it and exit. - if (header.Opcode == MessageOpcode.Ping || header.Opcode == MessageOpcode.Pong) - { - await HandleReceivedPingPongAsync(header, cancellationToken).ConfigureAwait(false); - continue; - } - else if (header.Opcode == MessageOpcode.Close) - { - return await HandleReceivedCloseAsync(header, cancellationToken).ConfigureAwait(false); - } - - // If this is a continuation, replace the opcode with the one of the message it's continuing - if (header.Opcode == MessageOpcode.Continuation) - { - header.Opcode = _lastReceiveHeader.Opcode; - } - - // The message should now be a binary or text message. Handle it by reading the payload and returning the contents. - Debug.Assert(header.Opcode == MessageOpcode.Binary || header.Opcode == MessageOpcode.Text, $"Unexpected opcode {header.Opcode}"); - - // If there's no data to read, return an appropriate result. - int bytesToRead = (int)Math.Min(payloadBuffer.Count, header.PayloadLength); - if (bytesToRead == 0) - { - _lastReceiveHeader = header; - return new WebSocketReceiveResult( - 0, - header.Opcode == MessageOpcode.Text ? WebSocketMessageType.Text : WebSocketMessageType.Binary, - header.PayloadLength == 0 ? header.Fin : false); - } - - // Otherwise, read as much of the payload as we can efficiently, and upate the header to reflect how much data - // remains for future reads. - - if (_receiveBufferCount == 0) - { - await EnsureBufferContainsAsync(1, cancellationToken, throwOnPrematureClosure: false).ConfigureAwait(false); - } - - int bytesToCopy = Math.Min(bytesToRead, _receiveBufferCount); - if (_isServer) - { - _receivedMaskOffsetOffset = ApplyMask(_receiveBuffer, _receiveBufferOffset, header.Mask, _receivedMaskOffsetOffset, bytesToCopy); - } - Buffer.BlockCopy(_receiveBuffer, _receiveBufferOffset, payloadBuffer.Array, payloadBuffer.Offset, bytesToCopy); - ConsumeFromBuffer(bytesToCopy); - header.PayloadLength -= bytesToCopy; - - // If this a text message, validate that it contains valid UTF8. - if (header.Opcode == MessageOpcode.Text && - !TryValidateUtf8(new ArraySegment(payloadBuffer.Array, payloadBuffer.Offset, bytesToCopy), header.Fin, _utf8TextState)) - { - await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.InvalidPayloadData, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false); - } - - _lastReceiveHeader = header; - return new WebSocketReceiveResult( - bytesToCopy, - header.Opcode == MessageOpcode.Text ? WebSocketMessageType.Text : WebSocketMessageType.Binary, - bytesToCopy == 0 || (header.Fin && header.PayloadLength == 0)); - } - } - catch (Exception exc) - { - throw _state == WebSocketState.Aborted ? - new WebSocketException(WebSocketError.InvalidState, SR.Format(SR.net_WebSockets_InvalidState_ClosedOrAborted, "System.Net.WebSockets.InternalClientWebSocket", "Aborted"), exc) : - new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); - } - finally - { - registration.Dispose(); - } - } - - /// Processes a received close message. - /// The message header. - /// The cancellation token to use to cancel the websocket. - /// The received result message. - private async Task HandleReceivedCloseAsync( - MessageHeader header, CancellationToken cancellationToken) - { - lock (StateUpdateLock) - { - _receivedCloseFrame = true; - if (_state < WebSocketState.CloseReceived) - { - _state = WebSocketState.CloseReceived; - } - } - - WebSocketCloseStatus closeStatus = WebSocketCloseStatus.NormalClosure; - string closeStatusDescription = string.Empty; - - // Handle any payload by parsing it into the close status and description. - if (header.PayloadLength == 1) - { - // The close payload length can be 0 or >= 2, but not 1. - await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false); - } - else if (header.PayloadLength >= 2) - { - if (_receiveBufferCount < header.PayloadLength) - { - await EnsureBufferContainsAsync((int)header.PayloadLength, cancellationToken).ConfigureAwait(false); - } - - if (_isServer) - { - ApplyMask(_receiveBuffer, _receiveBufferOffset, header.Mask, 0, header.PayloadLength); - } - - closeStatus = (WebSocketCloseStatus)(_receiveBuffer[_receiveBufferOffset] << 8 | _receiveBuffer[_receiveBufferOffset + 1]); - if (!IsValidCloseStatus(closeStatus)) - { - await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false); - } - - if (header.PayloadLength > 2) - { - try - { - closeStatusDescription = s_textEncoding.GetString(_receiveBuffer, _receiveBufferOffset + 2, (int)header.PayloadLength - 2); - } - catch (DecoderFallbackException exc) - { - await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken, exc).ConfigureAwait(false); - } - } - ConsumeFromBuffer((int)header.PayloadLength); - } - - // Store the close status and description onto the instance. - _closeStatus = closeStatus; - _closeStatusDescription = closeStatusDescription; - - // And return them as part of the result message. - return new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, closeStatus, closeStatusDescription); - } - - /// Processes a received ping or pong message. - /// The message header. - /// The cancellation token to use to cancel the websocket. - private async Task HandleReceivedPingPongAsync(MessageHeader header, CancellationToken cancellationToken) - { - // Consume any (optional) payload associated with the ping/pong. - if (header.PayloadLength > 0 && _receiveBufferCount < header.PayloadLength) - { - await EnsureBufferContainsAsync((int)header.PayloadLength, cancellationToken).ConfigureAwait(false); - } - - // If this was a ping, send back a pong response. - if (header.Opcode == MessageOpcode.Ping) - { - if (_isServer) - { - ApplyMask(_receiveBuffer, _receiveBufferOffset, header.Mask, 0, header.PayloadLength); - } - - await SendFrameAsync( - MessageOpcode.Pong, true, - new ArraySegment(_receiveBuffer, _receiveBufferOffset, (int)header.PayloadLength), cancellationToken).ConfigureAwait(false); - } - - // Regardless of whether it was a ping or pong, we no longer need the payload. - if (header.PayloadLength > 0) - { - ConsumeFromBuffer((int)header.PayloadLength); - } - } - - /// Check whether a close status is valid according to the RFC. - /// The status to validate. - /// true if the status if valid; otherwise, false. - private static bool IsValidCloseStatus(WebSocketCloseStatus closeStatus) - { - // 0-999: "not used" - // 1000-2999: reserved for the protocol; we need to check individual codes manually - // 3000-3999: reserved for use by higher-level code - // 4000-4999: reserved for private use - // 5000-: not mentioned in RFC - - if (closeStatus < (WebSocketCloseStatus)1000 || closeStatus >= (WebSocketCloseStatus)5000) - { - return false; - } - - if (closeStatus >= (WebSocketCloseStatus)3000) - { - return true; - } - - switch (closeStatus) // check for the 1000-2999 range known codes - { - case WebSocketCloseStatus.EndpointUnavailable: - case WebSocketCloseStatus.InternalServerError: - case WebSocketCloseStatus.InvalidMessageType: - case WebSocketCloseStatus.InvalidPayloadData: - case WebSocketCloseStatus.MandatoryExtension: - case WebSocketCloseStatus.MessageTooBig: - case WebSocketCloseStatus.NormalClosure: - case WebSocketCloseStatus.PolicyViolation: - case WebSocketCloseStatus.ProtocolError: - return true; - - default: - return false; - } - } - - /// Send a close message to the server and throw an exception, in response to getting bad data from the server. - /// The close status code to use. - /// The error reason. - /// The CancellationToken used to cancel the websocket. - /// An optional inner exception to include in the thrown exception. - private async Task CloseWithReceiveErrorAndThrowAsync( - WebSocketCloseStatus closeStatus, WebSocketError error, CancellationToken cancellationToken, Exception innerException = null) - { - // Close the connection if it hasn't already been closed - if (!_sentCloseFrame) - { - await CloseOutputAsync(closeStatus, string.Empty, cancellationToken).ConfigureAwait(false); - } - - // Dump our receive buffer; we're in a bad state to do any further processing - _receiveBufferCount = 0; - - // Let the caller know we've failed - throw new WebSocketException(error, innerException); - } - - /// Parses a message header from the buffer. This assumes the header is in the buffer. - /// The read header. - /// true if a header was read; false if the header was invalid. - private bool TryParseMessageHeaderFromReceiveBuffer(out MessageHeader resultHeader) - { - Debug.Assert(_receiveBufferCount >= 2, $"Expected to at least have the first two bytes of the header."); - - var header = new MessageHeader(); - - header.Fin = (_receiveBuffer[_receiveBufferOffset] & 0x80) != 0; - bool reservedSet = (_receiveBuffer[_receiveBufferOffset] & 0x70) != 0; - header.Opcode = (MessageOpcode)(_receiveBuffer[_receiveBufferOffset] & 0xF); - - bool masked = (_receiveBuffer[_receiveBufferOffset + 1] & 0x80) != 0; - header.PayloadLength = _receiveBuffer[_receiveBufferOffset + 1] & 0x7F; - - ConsumeFromBuffer(2); - - // Read the remainder of the payload length, if necessary - if (header.PayloadLength == 126) - { - Debug.Assert(_receiveBufferCount >= 2, $"Expected to have two bytes for the payload length."); - header.PayloadLength = (_receiveBuffer[_receiveBufferOffset] << 8) | _receiveBuffer[_receiveBufferOffset + 1]; - ConsumeFromBuffer(2); - } - else if (header.PayloadLength == 127) - { - Debug.Assert(_receiveBufferCount >= 8, $"Expected to have eight bytes for the payload length."); - header.PayloadLength = 0; - for (int i = 0; i < 8; i++) - { - header.PayloadLength = (header.PayloadLength << 8) | _receiveBuffer[_receiveBufferOffset + i]; - } - ConsumeFromBuffer(8); - } - - bool shouldFail = reservedSet; - if (masked) - { - if (!_isServer) - { - shouldFail = true; - } - header.Mask = CombineMaskBytes(_receiveBuffer, _receiveBufferOffset); - - // Consume the mask bytes - ConsumeFromBuffer(4); - } - - // Do basic validation of the header - switch (header.Opcode) - { - case MessageOpcode.Continuation: - if (_lastReceiveHeader.Fin) - { - // Can't continue from a final message - shouldFail = true; - } - break; - - case MessageOpcode.Binary: - case MessageOpcode.Text: - if (!_lastReceiveHeader.Fin) - { - // Must continue from a non-final message - shouldFail = true; - } - break; - - case MessageOpcode.Close: - case MessageOpcode.Ping: - case MessageOpcode.Pong: - if (header.PayloadLength > MaxControlPayloadLength || !header.Fin) - { - // Invalid control messgae - shouldFail = true; - } - break; - - default: - // Unknown opcode - shouldFail = true; - break; - } - - // Return the read header - resultHeader = header; - return !shouldFail; - } - - /// Send a close message, then receive until we get a close response message. - /// The close status to send. - /// The close status description to send. - /// The CancellationToken to use to cancel the websocket. - private async Task CloseAsyncPrivate(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) - { - // Send the close message. Skip sending a close frame if we're currently in a CloseSent state, - // for example having just done a CloseOutputAsync. - if (!_sentCloseFrame) - { - await SendCloseFrameAsync(closeStatus, statusDescription, cancellationToken).ConfigureAwait(false); - } - - // We should now either be in a CloseSent case (because we just sent one), or in a CloseReceived state, in case - // there was a concurrent receive that ended up handling an immediate close frame response from the server. - // Of course it could also be Aborted if something happened concurrently to cause things to blow up. - Debug.Assert( - State == WebSocketState.CloseSent || - State == WebSocketState.CloseReceived || - State == WebSocketState.Aborted, - $"Unexpected state {State}."); - - // Wait until we've received a close response - byte[] closeBuffer = new byte[MaxMessageHeaderLength + MaxControlPayloadLength]; - while (!_receivedCloseFrame) - { - Debug.Assert(!Monitor.IsEntered(StateUpdateLock), $"{nameof(StateUpdateLock)} must never be held when acquiring {nameof(ReceiveAsyncLock)}"); - Task receiveTask; - lock (ReceiveAsyncLock) - { - // Now that we're holding the ReceiveAsyncLock, double-check that we've not yet received the close frame. - // It could have been received between our check above and now due to a concurrent receive completing. - if (_receivedCloseFrame) - { - break; - } - - // We've not yet processed a received close frame, which means we need to wait for a received close to complete. - // There may already be one in flight, in which case we want to just wait for that one rather than kicking off - // another (we don't support concurrent receive operations). We need to kick off a new receive if either we've - // never issued a receive or if the last issued receive completed for reasons other than a close frame. There is - // a race condition here, e.g. if there's a in-flight receive that completes after we check, but that's fine: worst - // case is we then await it, find that it's not what we need, and try again. - receiveTask = _lastReceiveAsync; - if (receiveTask == null || - (receiveTask.Status == TaskStatus.RanToCompletion && receiveTask.Result.MessageType != WebSocketMessageType.Close)) - { - _lastReceiveAsync = receiveTask = ReceiveAsyncPrivate(new ArraySegment(closeBuffer), cancellationToken); - } - } - - // Wait for whatever receive task we have. We'll then loop around again to re-check our state. - Debug.Assert(receiveTask != null); - await receiveTask.ConfigureAwait(false); - } - - // We're closed. Close the connection and update the status. - lock (StateUpdateLock) - { - DisposeCore(); - if (_state < WebSocketState.Closed) - { - _state = WebSocketState.Closed; - } - } - } - - /// Sends a close message to the server. - /// The close status to send. - /// The close status description to send. - /// The CancellationToken to use to cancel the websocket. - private async Task SendCloseFrameAsync(WebSocketCloseStatus closeStatus, string closeStatusDescription, CancellationToken cancellationToken) - { - // Close payload is two bytes containing the close status followed by a UTF8-encoding of the status description, if it exists. - - byte[] buffer; - if (string.IsNullOrEmpty(closeStatusDescription)) - { - buffer = new byte[2]; - } - else - { - buffer = new byte[2 + s_textEncoding.GetByteCount(closeStatusDescription)]; - int encodedLength = s_textEncoding.GetBytes(closeStatusDescription, 0, closeStatusDescription.Length, buffer, 2); - Debug.Assert(buffer.Length - 2 == encodedLength, $"GetByteCount and GetBytes encoded count didn't match"); - } - - ushort closeStatusValue = (ushort)closeStatus; - buffer[0] = (byte)(closeStatusValue >> 8); - buffer[1] = (byte)(closeStatusValue & 0xFF); - - await SendFrameAsync(MessageOpcode.Close, true, new ArraySegment(buffer), cancellationToken).ConfigureAwait(false); - - lock (StateUpdateLock) - { - _sentCloseFrame = true; - if (_state <= WebSocketState.CloseReceived) - { - _state = WebSocketState.CloseSent; - } - } - } - - private void ConsumeFromBuffer(int count) - { - Debug.Assert(count >= 0, $"Expected non-negative count, got {count}"); - Debug.Assert(count <= _receiveBufferCount, $"Trying to consume {count}, which is more than exists {_receiveBufferCount}"); - _receiveBufferCount -= count; - _receiveBufferOffset += count; - } - - private async Task EnsureBufferContainsAsync(int minimumRequiredBytes, CancellationToken cancellationToken, bool throwOnPrematureClosure = true) - { - Debug.Assert(minimumRequiredBytes <= _receiveBuffer.Length, $"Requested number of bytes {minimumRequiredBytes} must not exceed {_receiveBuffer.Length}"); - - // If we don't have enough data in the buffer to satisfy the minimum required, read some more. - if (_receiveBufferCount < minimumRequiredBytes) - { - // If there's any data in the buffer, shift it down. - if (_receiveBufferCount > 0) - { - Buffer.BlockCopy(_receiveBuffer, _receiveBufferOffset, _receiveBuffer, 0, _receiveBufferCount); - } - _receiveBufferOffset = 0; - - // While we don't have enough data, read more. - while (_receiveBufferCount < minimumRequiredBytes) - { - int numRead = await _stream.ReadAsync(_receiveBuffer, _receiveBufferCount, _receiveBuffer.Length - _receiveBufferCount, cancellationToken).ConfigureAwait(false); - Debug.Assert(numRead >= 0, $"Expected non-negative bytes read, got {numRead}"); - _receiveBufferCount += numRead; - if (numRead == 0) - { - // The connection closed before we were able to read everything we needed. - // If it was due to use being disposed, fail. If it was due to the connection - // being closed and it wasn't expected, fail. If it was due to the connection - // being closed and that was expected, exit gracefully. - if (_disposed) - { - throw new ObjectDisposedException("ClientWebSocket"); - } - else if (throwOnPrematureClosure) - { - throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely); - } - break; - } - } - } - } - - /// - /// Grows the specified buffer if it's not at least the specified minimum length. - /// Data is not copied if the buffer is grown. - /// - private static void EnsureBufferLength(ref byte[] buffer, int minLength) - { - if (buffer == null || buffer.Length < minLength) - { - buffer = new byte[minLength]; - } - } - - private static unsafe int CombineMaskBytes(byte[] buffer, int maskOffset) => - BitConverter.ToInt32(buffer, maskOffset); - - /// Applies a mask to a portion of a byte array. - /// The buffer to which the mask should be applied. - /// The offset into at which the mask should start to be applied. - /// The array containing the mask to apply. - /// The offset into of the mask to apply of length . - /// The next position offset from of which by to apply next from the mask. - /// The number of bytes starting from to which the mask should be applied. - /// The updated maskOffsetOffset value. - private static int ApplyMask(byte[] toMask, int toMaskOffset, byte[] mask, int maskOffset, int maskOffsetIndex, long count) - { - Debug.Assert(maskOffsetIndex < MaskLength, $"Unexpected {nameof(maskOffsetIndex)}: {maskOffsetIndex}"); - Debug.Assert(mask.Length >= MaskLength + maskOffset, $"Unexpected inputs: {mask.Length}, {maskOffset}"); - return ApplyMask(toMask, toMaskOffset, CombineMaskBytes(mask, maskOffset), maskOffsetIndex, count); - } - - /// Applies a mask to a portion of a byte array. - /// The buffer to which the mask should be applied. - /// The offset into at which the mask should start to be applied. - /// The four-byte mask, stored as an Int32. - /// The index into the mask. - /// The number of bytes to mask. - /// The next index into the mask to be used for future applications of the mask. - private static unsafe int ApplyMask(byte[] toMask, int toMaskOffset, int mask, int maskIndex, long count) - { - Debug.Assert(toMaskOffset <= toMask.Length - count, $"Unexpected inputs: {toMaskOffset}, {toMask.Length}, {count}"); - Debug.Assert(maskIndex < sizeof(int), $"Unexpected {nameof(maskIndex)}: {maskIndex}"); - - byte* maskPtr = (byte*)&mask; - fixed (byte* toMaskPtr = toMask) - { - byte* p = toMaskPtr + toMaskOffset; - byte* end = p + count; - while (p < end) - { - *p++ ^= maskPtr[maskIndex]; - maskIndex = (maskIndex + 1) & 3; // & 3 == faster % MaskLength - } - return maskIndex; - } - } - - /// Aborts the websocket and throws an exception if an existing operation is in progress. - private void ThrowIfOperationInProgress(Task operationTask, [CallerMemberName] string methodName = null) - { - if (operationTask != null && !operationTask.IsCompleted) - { - Abort(); - throw new InvalidOperationException(SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, methodName)); - } - } - - /// Creates an OperationCanceledException instance, using a default message and the specified inner exception and token. - private static Exception CreateOperationCanceledException(Exception innerException, CancellationToken cancellationToken = default(CancellationToken)) - { - return new OperationCanceledException( - new OperationCanceledException().Message, - innerException, - cancellationToken); - } - - // From https://raw.githubusercontent.com/aspnet/WebSockets/dev/src/Microsoft.AspNetCore.WebSockets.Protocol/Utilities.cs - // Performs a stateful validation of UTF-8 bytes. - // It checks for valid formatting, overlong encodings, surrogates, and value ranges. - private static bool TryValidateUtf8(ArraySegment arraySegment, bool endOfMessage, Utf8MessageState state) - { - for (int i = arraySegment.Offset; i < arraySegment.Offset + arraySegment.Count;) - { - // Have we started a character sequence yet? - if (!state.SequenceInProgress) - { - // The first byte tells us how many bytes are in the sequence. - state.SequenceInProgress = true; - byte b = arraySegment.Array[i]; - i++; - if ((b & 0x80) == 0) // 0bbbbbbb, single byte - { - state.AdditionalBytesExpected = 0; - state.CurrentDecodeBits = b & 0x7F; - state.ExpectedValueMin = 0; - } - else if ((b & 0xC0) == 0x80) - { - // Misplaced 10bbbbbb continuation byte. This cannot be the first byte. - return false; - } - else if ((b & 0xE0) == 0xC0) // 110bbbbb 10bbbbbb - { - state.AdditionalBytesExpected = 1; - state.CurrentDecodeBits = b & 0x1F; - state.ExpectedValueMin = 0x80; - } - else if ((b & 0xF0) == 0xE0) // 1110bbbb 10bbbbbb 10bbbbbb - { - state.AdditionalBytesExpected = 2; - state.CurrentDecodeBits = b & 0xF; - state.ExpectedValueMin = 0x800; - } - else if ((b & 0xF8) == 0xF0) // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb - { - state.AdditionalBytesExpected = 3; - state.CurrentDecodeBits = b & 0x7; - state.ExpectedValueMin = 0x10000; - } - else // 111110bb & 1111110b & 11111110 && 11111111 are not valid - { - return false; - } - } - while (state.AdditionalBytesExpected > 0 && i < arraySegment.Offset + arraySegment.Count) - { - byte b = arraySegment.Array[i]; - if ((b & 0xC0) != 0x80) - { - return false; - } - - i++; - state.AdditionalBytesExpected--; - - // Each continuation byte carries 6 bits of data 0x10bbbbbb. - state.CurrentDecodeBits = (state.CurrentDecodeBits << 6) | (b & 0x3F); - - if (state.AdditionalBytesExpected == 1 && state.CurrentDecodeBits >= 0x360 && state.CurrentDecodeBits <= 0x37F) - { - // This is going to end up in the range of 0xD800-0xDFFF UTF-16 surrogates that are not allowed in UTF-8; - return false; - } - if (state.AdditionalBytesExpected == 2 && state.CurrentDecodeBits >= 0x110) - { - // This is going to be out of the upper Unicode bound 0x10FFFF. - return false; - } - } - if (state.AdditionalBytesExpected == 0) - { - state.SequenceInProgress = false; - if (state.CurrentDecodeBits < state.ExpectedValueMin) - { - // Overlong encoding (e.g. using 2 bytes to encode something that only needed 1). - return false; - } - } - } - if (endOfMessage && state.SequenceInProgress) - { - return false; - } - return true; - } - - private sealed class Utf8MessageState - { - internal bool SequenceInProgress; - internal int AdditionalBytesExpected; - internal int ExpectedValueMin; - internal int CurrentDecodeBits; - } - - private enum MessageOpcode : byte - { - Continuation = 0x0, - Text = 0x1, - Binary = 0x2, - Close = 0x8, - Ping = 0x9, - Pong = 0xA - } - - [StructLayout(LayoutKind.Auto)] - private struct MessageHeader - { - internal MessageOpcode Opcode; - internal bool Fin; - internal long PayloadLength; - internal int Mask; - } - } -} diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/WebSocketTests.cs deleted file mode 100644 index cf919cba77..0000000000 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/WebSocketTests.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Net.Http; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Testing.xunit; -using Xunit; - -namespace Microsoft.AspNetCore.Server.HttpSys.Listener -{ - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] - public class WebSocketTests - { - [ConditionalFact] - public async Task WebSocketAccept_AfterHeadersSent_Throws() - { - string address; - using (var server = Utilities.CreateHttpServer(out address)) - { - Task clientTask = SendRequestAsync(address); - - var context = await server.AcceptAsync(Utilities.DefaultTimeout); - byte[] body = Encoding.UTF8.GetBytes("Hello World"); - context.Response.Body.Write(body, 0, body.Length); - - await Assert.ThrowsAsync(async () => await context.AcceptWebSocketAsync()); - context.Dispose(); - HttpResponseMessage response = await clientTask; - Assert.Equal(200, (int)response.StatusCode); - Assert.Equal("Hello World", await response.Content.ReadAsStringAsync()); - } - } - - [ConditionalFact] - public async Task WebSocketAccept_Success() - { - string address; - using (var server = Utilities.CreateHttpServer(out address)) - { - Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); - - var context = await server.AcceptAsync(Utilities.DefaultTimeout); - Assert.True(context.IsUpgradableRequest); - WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); - WebSocket clientWebSocket = await clientTask; - serverWebSocket.Dispose(); - clientWebSocket.Dispose(); - } - } - - [ConditionalFact] - public async Task WebSocketAccept_SendAndReceive_Success() - { - string address; - using (var server = Utilities.CreateHttpServer(out address)) - { - Task clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address)); - - var context = await server.AcceptAsync(Utilities.DefaultTimeout); - Assert.True(context.IsWebSocketRequest); - WebSocket serverWebSocket = await context.AcceptWebSocketAsync(); - WebSocket clientWebSocket = await clientTask; - - byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; - await clientWebSocket.SendAsync(new ArraySegment(clientBuffer, 0, 3), WebSocketMessageType.Binary, true, CancellationToken.None); - - byte[] serverBuffer = new byte[clientBuffer.Length]; - var result = await serverWebSocket.ReceiveAsync(new ArraySegment(serverBuffer, 0, serverBuffer.Length), CancellationToken.None); - Assert.Equal(clientBuffer, serverBuffer); - - await serverWebSocket.SendAsync(new ArraySegment(serverBuffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); - - byte[] clientEchoBuffer = new byte[clientBuffer.Length]; - result = await clientWebSocket.ReceiveAsync(new ArraySegment(clientEchoBuffer), CancellationToken.None); - Assert.Equal(clientBuffer, clientEchoBuffer); - - serverWebSocket.Dispose(); - clientWebSocket.Dispose(); - } - } - - private string ConvertToWebSocketAddress(string address) - { - var builder = new UriBuilder(address); - builder.Scheme = "ws"; - return builder.ToString(); - } - - private async Task SendRequestAsync(string uri) - { - using (HttpClient client = new HttpClient()) - { - return await client.GetAsync(uri); - } - } - - private async Task SendWebSocketRequestAsync(string address) - { - ClientWebSocket client = new ClientWebSocket(); - await client.ConnectAsync(new Uri(address), CancellationToken.None); - return client; - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/WebSocketTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/WebSocketTests.cs deleted file mode 100644 index 92baa968ab..0000000000 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/WebSocketTests.cs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Net.Http; -using System.Net.WebSockets; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Testing.xunit; -using Xunit; - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] - public class WebSocketTests - { - [ConditionalFact] - public async Task WebSocketTests_SupportKeys_Present() - { - string address; - using (Utilities.CreateHttpServer(out address, httpContext => - { - try - { - var webSocketFeature = httpContext.Features.Get(); - Assert.NotNull(webSocketFeature); - } - catch (Exception ex) - { - return httpContext.Response.WriteAsync(ex.ToString()); - } - return Task.FromResult(0); - })) - { - HttpResponseMessage response = await SendRequestAsync(address); - Assert.Equal(200, (int)response.StatusCode); - Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); - Assert.Equal(0, response.Content.Headers.ContentLength); - Assert.Equal(string.Empty, response.Content.ReadAsStringAsync().Result); - } - } - - [ConditionalFact] - public async Task WebSocketTests_AfterHeadersSent_Throws() - { - bool? upgradeThrew = null; - string address; - using (Utilities.CreateHttpServer(out address, async httpContext => - { - await httpContext.Response.WriteAsync("Hello World"); - try - { - var webSocketFeature = httpContext.Features.Get(); - Assert.NotNull(webSocketFeature); - await webSocketFeature.AcceptAsync(null); - upgradeThrew = false; - } - catch (InvalidOperationException) - { - upgradeThrew = true; - } - })) - { - HttpResponseMessage response = await SendRequestAsync(address); - Assert.Equal(200, (int)response.StatusCode); - Assert.True(upgradeThrew.Value); - } - } - - [ConditionalFact] - public async Task WebSocketAccept_Success() - { - ManualResetEvent waitHandle = new ManualResetEvent(false); - bool? upgraded = null; - string address; - using (Utilities.CreateHttpServer(out address, async httpContext => - { - var webSocketFeature = httpContext.Features.Get(); - Assert.NotNull(webSocketFeature); - Assert.True(webSocketFeature.IsWebSocketRequest); - await webSocketFeature.AcceptAsync(null); - upgraded = true; - waitHandle.Set(); - })) - { - using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(ConvertToWebSocketAddress(address))) - { - Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); - Assert.True(upgraded.HasValue, "Upgraded not set"); - Assert.True(upgraded.Value, "Upgrade failed"); - } - } - } - - [ConditionalFact] - public async Task WebSocketAccept_WithOnStarting_CallbackCalled() - { - var callbackCalled = false; - var waitHandle = new ManualResetEvent(false); - bool? upgraded = null; - string address; - using (Utilities.CreateHttpServer(out address, async httpContext => - { - httpContext.Response.OnStarting(_ => - { - callbackCalled = true; - return Task.FromResult(0); - }, null); - var webSocketFeature = httpContext.Features.Get(); - Assert.NotNull(webSocketFeature); - Assert.True(webSocketFeature.IsWebSocketRequest); - await webSocketFeature.AcceptAsync(null); - upgraded = true; - waitHandle.Set(); - })) - { - using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(ConvertToWebSocketAddress(address))) - { - Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); - Assert.True(upgraded.HasValue, "Upgraded not set"); - Assert.True(upgraded.Value, "Upgrade failed"); - Assert.True(callbackCalled, "Callback not called"); - } - } - } - - [ConditionalFact] - public async Task WebSocketAccept_SendAndReceive_Success() - { - byte[] clientBuffer = new byte[] { 0x00, 0x01, 0xFF, 0x00, 0x00 }; - string address; - using (Utilities.CreateHttpServer(out address, async httpContext => - { - var webSocketFeature = httpContext.Features.Get(); - Assert.NotNull(webSocketFeature); - Assert.True(webSocketFeature.IsWebSocketRequest); - var serverWebSocket = await webSocketFeature.AcceptAsync(null); - - byte[] serverBuffer = new byte[clientBuffer.Length]; - var result = await serverWebSocket.ReceiveAsync(new ArraySegment(serverBuffer, 0, serverBuffer.Length), CancellationToken.None); - Assert.Equal(clientBuffer, serverBuffer); - - await serverWebSocket.SendAsync(new ArraySegment(serverBuffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); - - })) - { - using (WebSocket clientWebSocket = await SendWebSocketRequestAsync(ConvertToWebSocketAddress(address))) - { - await clientWebSocket.SendAsync(new ArraySegment(clientBuffer, 0, 3), WebSocketMessageType.Binary, true, CancellationToken.None); - - byte[] clientEchoBuffer = new byte[clientBuffer.Length]; - var result = await clientWebSocket.ReceiveAsync(new ArraySegment(clientEchoBuffer), CancellationToken.None); - Assert.Equal(clientBuffer, clientEchoBuffer); - } - } - } - - private string ConvertToWebSocketAddress(string address) - { - var builder = new UriBuilder(address); - builder.Scheme = "ws"; - return builder.ToString(); - } - - private async Task SendRequestAsync(string uri) - { - using (HttpClient client = new HttpClient()) - { - return await client.GetAsync(uri); - } - } - - private async Task SendWebSocketRequestAsync(string address) - { - var client = new ClientWebSocket(); - await client.ConnectAsync(new Uri(address), CancellationToken.None); - return client; - } - } -} \ No newline at end of file From 7c84269bc32c615495252550ffeb3b916d43fb51 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Mon, 9 Jan 2017 16:54:20 -0800 Subject: [PATCH 447/597] Remove no longer implemented WebSocket feature from collection --- .../StandardFeatureCollection.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs index 0be7301b68..8af2ddb7ba 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs @@ -23,7 +23,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys { typeof(IHttpBufferingFeature), _identityFunc }, { typeof(IHttpRequestLifetimeFeature), _identityFunc }, { typeof(IHttpUpgradeFeature), _identityFunc }, - { typeof(IHttpWebSocketFeature), _identityFunc }, { typeof(IHttpAuthenticationFeature), _identityFunc }, { typeof(IHttpRequestIdentifierFeature), _identityFunc }, { typeof(RequestContext), ctx => ctx.RequestContext }, From e19dea255b8818e5efe06f7631f8cfac84b31eb1 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 11 Jan 2017 12:00:19 -0800 Subject: [PATCH 448/597] Remove obsolete code --- samples/SelfHostServer/Startup.cs | 18 +---- .../HttpSysListener.cs | 2 +- .../HttpSysOptions.cs | 1 - .../NativeInterop/ContextAttribute.cs | 53 --------------- .../NativeInterop/HttpApi.cs | 68 +------------------ .../NativeInterop/SSPIHandle.cs | 31 --------- .../NativeInterop/SafeLoadLibrary.cs | 39 ----------- .../NativeInterop/SafeLocalFree.cs | 43 ------------ .../NativeInterop/SchProtocols.cs | 48 ------------- .../NativeInterop/SecurityStatus.cs | 51 -------------- .../NativeInterop/UnsafeNativeMethods.cs | 31 --------- .../RequestProcessing/Request.cs | 2 - .../RequestProcessing/Response.cs | 22 +----- .../RequestProcessing/ResponseBody.cs | 6 +- 14 files changed, 9 insertions(+), 406 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ContextAttribute.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SSPIHandle.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLoadLibrary.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFree.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SchProtocols.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SecurityStatus.cs diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index f327d5bb71..4d2726587c 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -1,7 +1,4 @@ using System; -using System.Net.WebSockets; -using System.Text; -using System.Threading; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -29,19 +26,8 @@ namespace SelfHostServer app.Run(async context => { - if (context.WebSockets.IsWebSocketRequest) - { - byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); - WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); - await webSocket.SendAsync(new ArraySegment(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None); - await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Goodbye", CancellationToken.None); - webSocket.Dispose(); - } - else - { - context.Response.ContentType = "text/plain"; - await context.Response.WriteAsync("Hello world from " + context.Request.Host + " at " + DateTime.Now); - } + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Hello world from " + context.Request.Host + " at " + DateTime.Now); }); } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs index a42c1f9af4..c2bea54052 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs @@ -398,7 +398,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys &httpResponse, null, &dataWritten, - SafeLocalFree.Zero, + IntPtr.Zero, 0, SafeNativeOverlapped.Zero, IntPtr.Zero); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index 4d8e4ccfaf..2c97b4ef39 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -15,7 +15,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys // The native request queue private long _requestQueueLength = DefaultRequestQueueLength; private RequestQueue _requestQueue; - private ILogger _logger = NullLogger.Instance; public HttpSysOptions() { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ContextAttribute.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ContextAttribute.cs deleted file mode 100644 index 6b2449091b..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ContextAttribute.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - internal enum ContextAttribute - { - // look into and - Sizes = 0x00, - Names = 0x01, - Lifespan = 0x02, - DceInfo = 0x03, - StreamSizes = 0x04, - // KeyInfo = 0x05, must not be used, see ConnectionInfo instead - Authority = 0x06, - // SECPKG_ATTR_PROTO_INFO = 7, - // SECPKG_ATTR_PASSWORD_EXPIRY = 8, - // SECPKG_ATTR_SESSION_KEY = 9, - PackageInfo = 0x0A, - // SECPKG_ATTR_USER_FLAGS = 11, - NegotiationInfo = 0x0C, - // SECPKG_ATTR_NATIVE_NAMES = 13, - // SECPKG_ATTR_FLAGS = 14, - // SECPKG_ATTR_USE_VALIDATED = 15, - // SECPKG_ATTR_CREDENTIAL_NAME = 16, - // SECPKG_ATTR_TARGET_INFORMATION = 17, - // SECPKG_ATTR_ACCESS_TOKEN = 18, - // SECPKG_ATTR_TARGET = 19, - // SECPKG_ATTR_AUTHENTICATION_ID = 20, - UniqueBindings = 0x19, - EndpointBindings = 0x1A, - ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27 - RemoteCertificate = 0x53, - LocalCertificate = 0x54, - RootStore = 0x55, - IssuerListInfoEx = 0x59, - ConnectionInfo = 0x5A, - // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock - // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr - // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo - // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData - // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates - // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy - // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult - // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group - // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo - // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo - // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo - // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures - // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT - UiInfo = 0x68, // sets SEcPkgContext_UiInfo - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs index 71b8bfe746..fbea3b2fbc 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs @@ -28,10 +28,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static extern uint HttpReceiveHttpRequest(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_REQUEST* pRequestBuffer, uint requestBufferLength, uint* pBytesReturned, SafeNativeOverlapped pOverlapped); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2* pHttpResponse, HTTP_CACHE_POLICY* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); + internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2* pHttpResponse, HTTP_CACHE_POLICY* pCachePolicy, uint* pBytesSent, IntPtr pReserved1, uint Reserved2, SafeNativeOverlapped pOverlapped, IntPtr pLogData); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK* pEntityChunks, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData); + internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK* pEntityChunks, uint* pBytesSent, IntPtr pReserved1, uint Reserved2, SafeNativeOverlapped pOverlapped, IntPtr pLogData); [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpCancelHttpRequest(SafeHandle requestQueueHandle, ulong requestId, IntPtr pOverlapped); @@ -633,65 +633,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys HTTP_AUTH_ENABLE_KERBEROS = 0x00000010, } - private const int HttpHeaderRequestMaximum = (int)HttpSysRequestHeader.UserAgent + 1; - private const int HttpHeaderResponseMaximum = (int)HttpSysResponseHeader.WwwAuthenticate + 1; - - internal static class HTTP_REQUEST_HEADER_ID - { - internal static string ToString(int position) - { - return _strings[position]; - } - - private static string[] _strings = - { - "Cache-Control", - "Connection", - "Date", - "Keep-Alive", - "Pragma", - "Trailer", - "Transfer-Encoding", - "Upgrade", - "Via", - "Warning", - - "Allow", - "Content-Length", - "Content-Type", - "Content-Encoding", - "Content-Language", - "Content-Location", - "Content-MD5", - "Content-Range", - "Expires", - "Last-Modified", - - "Accept", - "Accept-Charset", - "Accept-Encoding", - "Accept-Language", - "Authorization", - "Cookie", - "Expect", - "From", - "Host", - "If-Match", - - "If-Modified-Since", - "If-None-Match", - "If-Range", - "If-Unmodified-Since", - "Max-Forwards", - "Proxy-Authorization", - "Referer", - "Range", - "Te", - "Translate", - "User-Agent", - }; - } - internal static class HTTP_RESPONSE_HEADER_ID { private static string[] _strings = @@ -748,11 +689,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1; } - internal static string ToString(int position) - { - return _strings[position]; - } - internal enum Enum { HttpHeaderCacheControl = 0, // general-header [section 4.5] diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SSPIHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SSPIHandle.cs deleted file mode 100644 index 8a6801a3b6..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SSPIHandle.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct SSPIHandle - { - private IntPtr handleHi; - private IntPtr handleLo; - - public bool IsZero - { - get { return handleHi == IntPtr.Zero && handleLo == IntPtr.Zero; } - } - - internal void SetToInvalid() - { - handleHi = IntPtr.Zero; - handleLo = IntPtr.Zero; - } - - public override string ToString() - { - return handleHi.ToString("x") + ":" + handleLo.ToString("x"); - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLoadLibrary.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLoadLibrary.cs deleted file mode 100644 index c880a7f005..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLoadLibrary.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid - { - private const string KERNEL32 = "kernel32.dll"; - - public static readonly SafeLoadLibrary Zero = new SafeLoadLibrary(false); - - private SafeLoadLibrary() - : base(true) - { - } - - private SafeLoadLibrary(bool ownsHandle) - : base(ownsHandle) - { - } - - public static unsafe SafeLoadLibrary LoadLibraryEx(string library) - { - SafeLoadLibrary result = UnsafeNclNativeMethods.SafeNetHandles.LoadLibraryExW(library, null, 0); - if (result.IsInvalid) - { - result.SetHandleAsInvalid(); - } - return result; - } - - protected override bool ReleaseHandle() - { - return UnsafeNclNativeMethods.SafeNetHandles.FreeLibrary(handle); - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFree.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFree.cs deleted file mode 100644 index 06824eb438..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFree.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid - { - private const int LMEM_FIXED = 0; - private const int NULL = 0; - - // This returned handle cannot be modified by the application. - public static SafeLocalFree Zero = new SafeLocalFree(false); - - private SafeLocalFree() - : base(true) - { - } - - private SafeLocalFree(bool ownsHandle) - : base(ownsHandle) - { - } - - public static SafeLocalFree LocalAlloc(int cb) - { - SafeLocalFree result = UnsafeNclNativeMethods.SafeNetHandles.LocalAlloc(LMEM_FIXED, (UIntPtr)cb); - if (result.IsInvalid) - { - result.SetHandleAsInvalid(); - throw new OutOfMemoryException(); - } - return result; - } - - protected override bool ReleaseHandle() - { - return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero; - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SchProtocols.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SchProtocols.cs deleted file mode 100644 index 591d585172..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SchProtocols.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - using System; - using System.Globalization; - using System.Runtime.InteropServices; - - // From Schannel.h - [Flags] - internal enum SchProtocols - { - Zero = 0, - PctClient = 0x00000002, - PctServer = 0x00000001, - Pct = (PctClient | PctServer), - Ssl2Client = 0x00000008, - Ssl2Server = 0x00000004, - Ssl2 = (Ssl2Client | Ssl2Server), - Ssl3Client = 0x00000020, - Ssl3Server = 0x00000010, - Ssl3 = (Ssl3Client | Ssl3Server), - Tls10Client = 0x00000080, - Tls10Server = 0x00000040, - Tls10 = (Tls10Client | Tls10Server), - Tls11Client = 0x00000200, - Tls11Server = 0x00000100, - Tls11 = (Tls11Client | Tls11Server), - Tls12Client = 0x00000800, - Tls12Server = 0x00000400, - Tls12 = (Tls12Client | Tls12Server), - Ssl3Tls = (Ssl3 | Tls10), - UniClient = unchecked((int)0x80000000), - UniServer = 0x40000000, - Unified = (UniClient | UniServer), - ClientMask = (PctClient | Ssl2Client | Ssl3Client | Tls10Client | Tls11Client | Tls12Client | UniClient), - ServerMask = (PctServer | Ssl2Server | Ssl3Server | Tls10Server | Tls11Server | Tls12Server | UniServer) - } - - [StructLayout(LayoutKind.Sequential)] - internal struct Bindings - { - // see SecPkgContext_Bindings in - internal int BindingsLength; - internal IntPtr bindings; - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SecurityStatus.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SecurityStatus.cs deleted file mode 100644 index c46b114d8d..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SecurityStatus.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - internal enum SecurityStatus - { - // Success / Informational - OK = 0x00000000, - ContinueNeeded = unchecked((int)0x00090312), - CompleteNeeded = unchecked((int)0x00090313), - CompAndContinue = unchecked((int)0x00090314), - ContextExpired = unchecked((int)0x00090317), - CredentialsNeeded = unchecked((int)0x00090320), - Renegotiate = unchecked((int)0x00090321), - - // Errors - OutOfMemory = unchecked((int)0x80090300), - InvalidHandle = unchecked((int)0x80090301), - Unsupported = unchecked((int)0x80090302), - TargetUnknown = unchecked((int)0x80090303), - InternalError = unchecked((int)0x80090304), - PackageNotFound = unchecked((int)0x80090305), - NotOwner = unchecked((int)0x80090306), - CannotInstall = unchecked((int)0x80090307), - InvalidToken = unchecked((int)0x80090308), - CannotPack = unchecked((int)0x80090309), - QopNotSupported = unchecked((int)0x8009030A), - NoImpersonation = unchecked((int)0x8009030B), - LogonDenied = unchecked((int)0x8009030C), - UnknownCredentials = unchecked((int)0x8009030D), - NoCredentials = unchecked((int)0x8009030E), - MessageAltered = unchecked((int)0x8009030F), - OutOfSequence = unchecked((int)0x80090310), - NoAuthenticatingAuthority = unchecked((int)0x80090311), - IncompleteMessage = unchecked((int)0x80090318), - IncompleteCredentials = unchecked((int)0x80090320), - BufferNotEnough = unchecked((int)0x80090321), - WrongPrincipal = unchecked((int)0x80090322), - TimeSkew = unchecked((int)0x80090324), - UntrustedRoot = unchecked((int)0x80090325), - IllegalMessage = unchecked((int)0x80090326), - CertUnknown = unchecked((int)0x80090327), - CertExpired = unchecked((int)0x80090328), - AlgorithmMismatch = unchecked((int)0x80090331), - SecurityQosFailed = unchecked((int)0x80090332), - SmartcardLogonRequired = unchecked((int)0x8009033E), - UnsupportedPreauth = unchecked((int)0x80090343), - BadBinding = unchecked((int)0x80090346) - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs index e8a8daa505..c20f95f664 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs @@ -99,16 +99,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static extern int FreeContextBuffer( [In] IntPtr contextBuffer); -#if NETSTANDARD1_3 - [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] -#endif - internal static unsafe extern int QueryContextAttributesW( - ref SSPIHandle contextHandle, - [In] ContextAttribute attribute, - [In] void* buffer); - #if NETSTANDARD1_3 [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] #else @@ -116,13 +106,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys #endif internal static extern bool CloseHandle(IntPtr handle); -#if NETSTANDARD1_3 - [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif - internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes); - #if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_obsolete_LIB, EntryPoint = "LocalAlloc", SetLastError = true)] #else @@ -137,20 +120,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] #endif internal static extern IntPtr LocalFree(IntPtr handle); - -#if NETSTANDARD1_3 - [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] -#endif - internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags); - -#if NETSTANDARD1_3 - [DllImport(api_ms_win_core_libraryloader_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif - internal static extern unsafe bool FreeLibrary([In] IntPtr hModule); } // from tokenbinding.h diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 7741232aa6..78ed055204 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -214,8 +214,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys // HTTP.Sys allows you to upgrade anything to opaque unless content-length > 0 or chunked are specified. internal bool IsUpgradable => !HasEntityBody && ComNetOS.IsWin8orLater; - public string ContentType => Headers[HttpKnownHeaderNames.ContentType]; - internal ClaimsPrincipal User { get; } // Populates the client certificate. The result may be null if there is no client cert. diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index 9936d817ee..d9f095846e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -191,26 +191,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - public string ContentType - { - get - { - return Headers[HttpKnownHeaderNames.ContentType]; - } - set - { - CheckResponseStarted(); - if (string.IsNullOrEmpty(value)) - { - Headers.Remove(HttpKnownHeaderNames.ContentType); - } - else - { - Headers[HttpKnownHeaderNames.ContentType] = value; - } - } - } - /// /// Enable kernel caching for the response with the given timeout. Http.Sys determines if the response /// can be cached. @@ -368,7 +348,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys pResponse, &cachePolicy, &bytesSent, - SafeLocalFree.Zero, + IntPtr.Zero, 0, asyncResult == null ? SafeNativeOverlapped.Zero : asyncResult.NativeOverlapped, IntPtr.Zero); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs index 56a104a800..e34f3184e5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs @@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys (ushort)dataChunks.Length, pDataChunks, null, - SafeLocalFree.Zero, + IntPtr.Zero, 0, SafeNativeOverlapped.Zero, IntPtr.Zero); @@ -305,7 +305,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys asyncResult.DataChunkCount, asyncResult.DataChunks, &bytesSent, - SafeLocalFree.Zero, + IntPtr.Zero, 0, asyncResult.NativeOverlapped, IntPtr.Zero); @@ -600,7 +600,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys asyncResult.DataChunkCount, asyncResult.DataChunks, &bytesSent, - SafeLocalFree.Zero, + IntPtr.Zero, 0, asyncResult.NativeOverlapped, IntPtr.Zero); From 56bd85aaf2cdf7e948c6a9f0967bda27524953a5 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 24 Jan 2017 13:28:13 -0800 Subject: [PATCH 449/597] #298 Add a timeout for draining requests on shutdown --- .../HttpSysOptions.cs | 6 +++++ .../MessagePump.cs | 10 ++++++- .../ServerTests.cs | 26 ++++++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index 2c97b4ef39..fe0c6d1d64 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -81,6 +81,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + /// + /// The amount of time to wait for active requests to drain while the server is shutting down. + /// New requests will receive a 503 response in this time period. The default is 5 seconds. + /// + public TimeSpan ShutdownTimeout { get; set; } = TimeSpan.FromSeconds(5); + internal void SetRequestQueueLimit(RequestQueue requestQueue) { _requestQueue = requestQueue; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index bd6dbecc36..23921561c7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -221,7 +221,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (_outstandingRequests > 0) { LogHelper.LogInfo(_logger, "Stopping, waiting for " + _outstandingRequests + " request(s) to drain."); - _shutdownSignal.WaitOne(); + var drained = _shutdownSignal.WaitOne(Listener.Options.ShutdownTimeout); + if (drained) + { + LogHelper.LogInfo(_logger, "All requests drained successfully."); + } + else + { + LogHelper.LogInfo(_logger, "Timed out, terminating " + _outstandingRequests + " request(s)."); + } } // All requests are finished _listener.Dispose(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 2794e462ba..2ae94400fa 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task Server_ShutdownDurringRequest_Success() + public async Task Server_ShutdownDuringRequest_Success() { Task responseTask; ManualResetEvent received = new ManualResetEvent(false); @@ -87,6 +87,30 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Hello World", response); } + [ConditionalFact] + public async Task Server_ShutdownDuringLongRunningRequest_TimesOut() + { + Task responseTask; + var received = new ManualResetEvent(false); + bool? shutdown = null; + var waitForShutdown = new ManualResetEvent(false); + string address; + using (Utilities.CreateHttpServer(out address, httpContext => + { + received.Set(); + shutdown = waitForShutdown.WaitOne(TimeSpan.FromSeconds(15)); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); + })) + { + responseTask = SendRequestAsync(address); + Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + } + Assert.False(shutdown.HasValue); + waitForShutdown.Set(); + await Assert.ThrowsAsync(async () => await responseTask); + } + [ConditionalFact] public void Server_AppException_ClientReset() { From 119945ca02472f32b46bd24e53068a833403f19f Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 18 Jan 2017 15:16:45 -0800 Subject: [PATCH 450/597] Cache the ContentLength header value --- .../FeatureContext.cs | 4 +- .../HeaderDictionary.cs | 204 ------------------ .../RequestProcessing/HeaderCollection.cs | 53 ++++- .../RequestProcessing/Response.cs | 44 +--- .../RequestTests.cs | 2 +- 5 files changed, 57 insertions(+), 250 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index f63599a01c..fd1dd9da04 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _enableResponseCaching = enableResponseCaching; // Pre-initialize any fields that are not lazy at the lower level. - _requestHeaders = new HeaderDictionary(Request.Headers); + _requestHeaders = Request.Headers; _httpMethod = Request.Method; _path = Request.Path; _pathBase = Request.PathBase; @@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _user = _requestContext.User; _responseStream = new ResponseStream(requestContext.Response.Body, OnStart); - _responseHeaders = new HeaderDictionary(Response.Headers); + _responseHeaders = Response.Headers; } internal IFeatureCollection Features => _features; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs deleted file mode 100644 index fdc00eee2b..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HeaderDictionary.cs +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - /// - /// Represents a wrapper for RequestHeaders and ResponseHeaders. - /// - internal class HeaderDictionary : IHeaderDictionary - { - public HeaderDictionary(IDictionary store) - { - Store = store; - } - - private IDictionary Store { get; set; } - - /// - /// Get or sets the associated value from the collection as a single string. - /// - /// The header name. - /// the associated value from the collection as a StringValues or StringValues.Empty if the key is not present. - public StringValues this[string key] - { - get - { - StringValues value; - if (TryGetValue(key, out value)) - { - return value; - } - return StringValues.Empty; - } - set - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - if (StringValues.IsNullOrEmpty(value)) - { - Store.Remove(key); - } - else - { - Store[key] = value; - } - } - } - - /// - /// Throws KeyNotFoundException if the key is not present. - /// - /// The header name. - /// - StringValues IDictionary.this[string key] - { - get { return Store[key]; } - set { this[key] = value; } - } - - /// - /// Gets the number of elements contained in the ;. - /// - /// The number of elements contained in the . - public int Count - { - get { return Store.Count; } - } - - /// - /// Gets a value that indicates whether the is in read-only mode. - /// - /// true if the is in read-only mode; otherwise, false. - public bool IsReadOnly - { - get { return Store.IsReadOnly; } - } - - public ICollection Keys - { - get { return Store.Keys; } - } - - public ICollection Values - { - get { return Store.Values; } - } - - /// - /// Adds a new list of items to the collection. - /// - /// The item to add. - public void Add(KeyValuePair item) - { - Store.Add(item.Key, item.Value); - } - - /// - /// Adds the given header and values to the collection. - /// - /// The header name. - /// The header values. - public void Add(string key, StringValues value) - { - Store.Add(key, value); - } - - /// - /// Clears the entire list of objects. - /// - public void Clear() - { - Store.Clear(); - } - - /// - /// Returns a value indicating whether the specified object occurs within this collection. - /// - /// The item. - /// true if the specified object occurs within this collection; otherwise, false. - public bool Contains(KeyValuePair item) - { - return Store.Contains(item); - } - - /// - /// Determines whether the contains a specific key. - /// - /// The key. - /// true if the contains a specific key; otherwise, false. - public bool ContainsKey(string key) - { - return Store.ContainsKey(key); - } - - /// - /// Copies the elements to a one-dimensional Array instance at the specified index. - /// - /// The one-dimensional Array that is the destination of the specified objects copied from - /// the . - /// The zero-based index in at which copying begins. - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - Store.CopyTo(array, arrayIndex); - } - - /// - /// Removes the given item from the the collection. - /// - /// The item. - /// true if the specified object was removed from the collection; otherwise, false. - public bool Remove(KeyValuePair item) - { - return Store.Remove(item); - } - - /// - /// Removes the given header from the collection. - /// - /// The header name. - /// true if the specified object was removed from the collection; otherwise, false. - public bool Remove(string key) - { - return Store.Remove(key); - } - - /// - /// Retrieves a value from the dictionary. - /// - /// The header name. - /// The value. - /// true if the contains the key; otherwise, false. - public bool TryGetValue(string key, out StringValues value) - { - return Store.TryGetValue(key, out value); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return Store.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator> IEnumerable>.GetEnumerator() - { - return Store.GetEnumerator(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs index 4f6cd220e4..1eef943354 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs @@ -4,12 +4,17 @@ using System; using System.Collections; using System.Collections.Generic; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Server.HttpSys { - internal class HeaderCollection : IDictionary + internal class HeaderCollection : IHeaderDictionary { + private long? _contentLength; + private StringValues _contentLengthText; + public HeaderCollection() : this(new Dictionary(4, StringComparer.OrdinalIgnoreCase)) { @@ -75,6 +80,52 @@ namespace Microsoft.AspNetCore.Server.HttpSys get { return Store.Values; } } + public long? ContentLength + { + get + { + long value; + var rawValue = this[HttpKnownHeaderNames.ContentLength]; + + if (_contentLengthText.Equals(rawValue)) + { + return _contentLength; + } + + if (rawValue.Count == 1 && + !string.IsNullOrWhiteSpace(rawValue[0]) && + HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value)) + { + _contentLengthText = rawValue; + _contentLength = value; + return value; + } + + return null; + } + set + { + ThrowIfReadOnly(); + + if (value.HasValue) + { + if (value.Value < 0) + { + throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative."); + } + _contentLengthText = HeaderUtilities.FormatInt64(value.Value); + this[HttpKnownHeaderNames.ContentLength] = _contentLengthText; + _contentLength = value; + } + else + { + Remove(HttpKnownHeaderNames.ContentLength); + _contentLengthText = StringValues.Empty; + _contentLength = null; + } + } + } + public void Add(KeyValuePair item) { ThrowIfReadOnly(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index d9f095846e..31846b6541 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -147,48 +147,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys // Header accessors public long? ContentLength { - get - { - string contentLengthString = Headers[HttpKnownHeaderNames.ContentLength]; - long contentLength; - if (!string.IsNullOrWhiteSpace(contentLengthString)) - { - contentLengthString = contentLengthString.Trim(); - if (string.Equals(Constants.Zero, contentLengthString, StringComparison.Ordinal)) - { - return 0; - } - else if (long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out contentLength)) - { - return contentLength; - } - } - return null; - } - set - { - CheckResponseStarted(); - if (!value.HasValue) - { - Headers.Remove(HttpKnownHeaderNames.ContentLength); - } - else - { - if (value.Value < 0) - { - throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative."); - } - - if (value.Value == 0) - { - Headers[HttpKnownHeaderNames.ContentLength] = Constants.Zero; - } - else - { - Headers[HttpKnownHeaderNames.ContentLength] = value.Value.ToString(CultureInfo.InvariantCulture); - } - } - } + get { return Headers.ContentLength; } + set { Headers.ContentLength = value; } } /// diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs index bb4688ebf5..1e79dff31b 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("TEST", requestInfo.Method); requestInfo.Body = new MemoryStream(); Assert.IsType(requestInfo.Body); - var customHeaders = new HeaderDictionary(new HeaderCollection()); + var customHeaders = new HeaderCollection(); requestInfo.Headers = customHeaders; Assert.Same(customHeaders, requestInfo.Headers); requestInfo.Scheme = "abcd"; From bad8bc945a43cbd362b0a97fdf837356f09e7be0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 3 Feb 2017 13:51:17 -0800 Subject: [PATCH 451/597] Convert from project.json to csproj --- NuGet.config | 1 + WebListener.sln | 39 ++++++++++----- appveyor.yml | 3 +- build.ps1 | 2 +- build.sh | 2 +- {tools => build}/Key.snk | Bin build/common.props | 24 ++++++++++ global.json | 9 ---- samples/HotAddSample/HotAddSample.csproj | 12 +++++ samples/HotAddSample/HotAddSample.xproj | 17 ------- samples/HotAddSample/project.json | 23 --------- samples/SelfHostServer/App.config | 3 -- samples/SelfHostServer/SelfHostServer.csproj | 12 +++++ samples/SelfHostServer/SelfHostServer.xproj | 17 ------- samples/SelfHostServer/project.json | 23 --------- .../runtimeconfig.template.json | 5 ++ ...Microsoft.AspNetCore.Server.HttpSys.csproj | 21 ++++++++ .../Microsoft.AspNetCore.Server.HttpSys.xproj | 20 -------- .../Properties/AssemblyInfo.cs | 7 --- .../project.json | 45 ------------------ ...Core.Server.HttpSys.FunctionalTests.csproj | 25 ++++++++++ ...tCore.Server.HttpSys.FunctionalTests.xproj | 20 -------- .../project.json | 32 ------------- ...oft.AspNetCore.Server.HttpSys.Tests.csproj | 15 ++++++ ...soft.AspNetCore.Server.HttpSys.Tests.xproj | 20 -------- .../project.json | 19 -------- version.props | 7 +++ 27 files changed, 152 insertions(+), 271 deletions(-) rename {tools => build}/Key.snk (100%) create mode 100644 build/common.props delete mode 100644 global.json create mode 100644 samples/HotAddSample/HotAddSample.csproj delete mode 100644 samples/HotAddSample/HotAddSample.xproj delete mode 100644 samples/HotAddSample/project.json create mode 100644 samples/SelfHostServer/SelfHostServer.csproj delete mode 100644 samples/SelfHostServer/SelfHostServer.xproj delete mode 100644 samples/SelfHostServer/project.json create mode 100644 samples/SelfHostServer/runtimeconfig.template.json create mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.xproj delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/project.json create mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj delete mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj delete mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/project.json create mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj delete mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.xproj delete mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.Tests/project.json create mode 100644 version.props diff --git a/NuGet.config b/NuGet.config index 826a1f9035..6f9f028ca1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,6 +2,7 @@ + \ No newline at end of file diff --git a/WebListener.sln b/WebListener.sln index 21d618b148..de17b49c97 100644 --- a/WebListener.sln +++ b/WebListener.sln @@ -1,29 +1,41 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26202.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{99D5E5F3-88F5-4CCF-8D8C-717C8925DF09}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E183C826-1360-4DFF-9994-F33CED5C8525}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A1E31E3-2794-4CA3-B8E2-253E96BDE514}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.xproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.HttpSys.FunctionalTests", "test\Microsoft.AspNetCore.Server.HttpSys.FunctionalTests\Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj", "{4492FF4C-9032-411D-853F-46B01755E504}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.HttpSys", "src\Microsoft.AspNetCore.Server.HttpSys\Microsoft.AspNetCore.Server.HttpSys.xproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5E9B546C-17AC-4BDF-BCB3-5955D4755ED8}" ProjectSection(SolutionItems) = preProject - global.json = global.json + .travis.yml = .travis.yml + appveyor.yml = appveyor.yml + build.cmd = build.cmd + build.ps1 = build.ps1 + build.sh = build.sh + NuGet.config = NuGet.config + version.props = version.props EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HotAddSample", "samples\HotAddSample\HotAddSample.xproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.HttpSys.Tests", "test\Microsoft.AspNetCore.Server.HttpSys.Tests\Microsoft.AspNetCore.Server.HttpSys.Tests.xproj", "{E837249E-E666-4DF2-AFC3-7A4D70234F9F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.csproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.HttpSys.FunctionalTests", "test\Microsoft.AspNetCore.Server.HttpSys.FunctionalTests\Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj", "{4492FF4C-9032-411D-853F-46B01755E504}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.HttpSys", "src\Microsoft.AspNetCore.Server.HttpSys\Microsoft.AspNetCore.Server.HttpSys.csproj", "{B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HotAddSample", "samples\HotAddSample\HotAddSample.csproj", "{8BFA392A-8B67-4454-916B-67C545EDFAEF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.HttpSys.Tests", "test\Microsoft.AspNetCore.Server.HttpSys.Tests\Microsoft.AspNetCore.Server.HttpSys.Tests.csproj", "{E837249E-E666-4DF2-AFC3-7A4D70234F9F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{85914BA9-4168-48C5-9C3F-E2E8B1479A6E}" + ProjectSection(SolutionItems) = preProject + build\common.props = build\common.props + build\Key.snk = build\Key.snk + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -110,5 +122,6 @@ Global {B9F45F9D-D206-47F0-8E5F-54CE2F0BDF92} = {99D5E5F3-88F5-4CCF-8D8C-717C8925DF09} {8BFA392A-8B67-4454-916B-67C545EDFAEF} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {E837249E-E666-4DF2-AFC3-7A4D70234F9F} = {E183C826-1360-4DFF-9994-F33CED5C8525} + {85914BA9-4168-48C5-9C3F-E2E8B1479A6E} = {5E9B546C-17AC-4BDF-BCB3-5955D4755ED8} EndGlobalSection EndGlobal diff --git a/appveyor.yml b/appveyor.yml index b9a9bcd1e6..e31ecda1e0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,4 +10,5 @@ build_script: - build.cmd verify clone_depth: 1 test: off -deploy: off \ No newline at end of file +deploy: off +os: Visual Studio 2017 RC \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f2f99691a..0605b59c01 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index 4fd7ede788..07997d6c83 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi diff --git a/tools/Key.snk b/build/Key.snk similarity index 100% rename from tools/Key.snk rename to build/Key.snk diff --git a/build/common.props b/build/common.props new file mode 100644 index 0000000000..2abfaa7306 --- /dev/null +++ b/build/common.props @@ -0,0 +1,24 @@ + + + + + Microsoft ASP.NET Core + https://github.com/aspnet/HttpSysServer + git + $(MSBuildThisFileDirectory)Key.snk + true + true + 1.2.0-* + 1.6.2-* + $(VersionSuffix)-$(BuildNumber) + + + + + + + + + + + \ No newline at end of file diff --git a/global.json b/global.json deleted file mode 100644 index ec96aa7abe..0000000000 --- a/global.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "projects": [ - "src", - "test" - ], - "sdk": { - "version": "1.0.0-preview2-1-003180" - } -} \ No newline at end of file diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj new file mode 100644 index 0000000000..effb1b67e3 --- /dev/null +++ b/samples/HotAddSample/HotAddSample.csproj @@ -0,0 +1,12 @@ + + + net451;netcoreapp1.1 + + win7-x64 + Exe + + + + + + diff --git a/samples/HotAddSample/HotAddSample.xproj b/samples/HotAddSample/HotAddSample.xproj deleted file mode 100644 index 677fc90d52..0000000000 --- a/samples/HotAddSample/HotAddSample.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 8bfa392a-8b67-4454-916b-67c545edfaef - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/samples/HotAddSample/project.json b/samples/HotAddSample/project.json deleted file mode 100644 index e35173259b..0000000000 --- a/samples/HotAddSample/project.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Server.HttpSys": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*" - }, - "buildOptions": { - "emitEntryPoint": true - }, - "commands": { - "web": "HotAddSample" - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - } -} \ No newline at end of file diff --git a/samples/SelfHostServer/App.config b/samples/SelfHostServer/App.config index 73c9881fb6..3048ab74e7 100644 --- a/samples/SelfHostServer/App.config +++ b/samples/SelfHostServer/App.config @@ -1,8 +1,5 @@  - - - diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj new file mode 100644 index 0000000000..effb1b67e3 --- /dev/null +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -0,0 +1,12 @@ + + + net451;netcoreapp1.1 + + win7-x64 + Exe + + + + + + diff --git a/samples/SelfHostServer/SelfHostServer.xproj b/samples/SelfHostServer/SelfHostServer.xproj deleted file mode 100644 index d2eaad70ff..0000000000 --- a/samples/SelfHostServer/SelfHostServer.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 1236f93a-ac5c-4a77-9477-c88f040151ca - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/samples/SelfHostServer/project.json b/samples/SelfHostServer/project.json deleted file mode 100644 index 756b800031..0000000000 --- a/samples/SelfHostServer/project.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Server.HttpSys": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*" - }, - "buildOptions": { - "emitEntryPoint": true - }, - "commands": { - "web": "SelfHostServer" - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - } -} \ No newline at end of file diff --git a/samples/SelfHostServer/runtimeconfig.template.json b/samples/SelfHostServer/runtimeconfig.template.json new file mode 100644 index 0000000000..12467a6df8 --- /dev/null +++ b/samples/SelfHostServer/runtimeconfig.template.json @@ -0,0 +1,5 @@ +{ + "configProperties": { + "System.GC.Server": true + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj new file mode 100644 index 0000000000..79b143c29b --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -0,0 +1,21 @@ + + + + ASP.NET Core HTTP server that uses the Windows HTTP Server API. + net451;netstandard1.3 + $(NoWarn);CS1591 + true + true + aspnetcore;weblistener;httpsys + + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.xproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.xproj deleted file mode 100644 index 603e49e271..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - b9f45f9d-d206-47f0-8e5f-54ce2f0bdf92 - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs index 4fc9a7542d..3bc10f0e3c 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs @@ -1,13 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Reflection; -using System.Resources; using System.Runtime.CompilerServices; -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.HttpSys.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/project.json b/src/Microsoft.AspNetCore.Server.HttpSys/project.json deleted file mode 100644 index e5fc45a8c4..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/project.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core HTTP server that uses the Windows HTTP Server API.", - "packOptions": { - "tags": [ - "aspnetcore", - "weblistener", - "httpsys" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.Hosting": "1.2.0-*", - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "Microsoft.Net.Http.Headers": "1.2.0-*", - "NETStandard.Library": "1.6.2-*" - }, - "buildOptions": { - "allowUnsafe": true, - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "frameworks": { - "net451": {}, - "netstandard1.3": { - "dependencies": { - "Microsoft.Extensions.RuntimeEnvironment.Sources": { - "type": "build", - "version": "1.2.0-*" - }, - "System.Diagnostics.Contracts": "4.4.0-*", - "System.Net.WebSockets": "4.4.0-*", - "System.Security.Claims": "4.4.0-*", - "System.Security.Principal.Windows": "4.4.0-*", - "System.Threading.Overlapped": "4.4.0-*" - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj new file mode 100644 index 0000000000..a8aae54342 --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -0,0 +1,25 @@ + + + + netcoreapp1.1;net451 + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj deleted file mode 100644 index c510d82574..0000000000 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 4492ff4c-9032-411d-853f-46b01755e504 - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/project.json deleted file mode 100644 index 5ff0bc8524..0000000000 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/project.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" - }, - "testRunner": "xunit", - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Server.HttpSys": "1.2.0-*", - "Microsoft.AspNetCore.Testing": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - }, - "System.Net.Http.WinHttpHandler": "4.4.0-*", - "System.Net.WebSockets.Client": "4.4.0-*" - } - }, - "net451": { - "frameworkAssemblies": { - "System.DirectoryServices": "", - "System.Net.Http": "", - "System.Net.Http.WebRequest": "" - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj new file mode 100644 index 0000000000..b9e760080a --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp1.1;net451 + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.xproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.xproj deleted file mode 100644 index ed2140ef02..0000000000 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - e837249e-e666-4df2-afc3-7a4d70234f9f - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/project.json b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/project.json deleted file mode 100644 index fd020492de..0000000000 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/project.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "testRunner": "xunit", - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Server.HttpSys": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - } -} \ No newline at end of file diff --git a/version.props b/version.props new file mode 100644 index 0000000000..38c93687ab --- /dev/null +++ b/version.props @@ -0,0 +1,7 @@ + + + + 1.2.0 + preview1 + + \ No newline at end of file From d35e4c95504f22e27547dfda2ace0d041ad5d17b Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 14 Feb 2017 09:11:07 -0800 Subject: [PATCH 452/597] Bump test projects up to .NET 4.5.2 - aspnet/Testing#248 - xUnit no longer supports .NET 4.5.1 - build tests for desktop .NET only on Windows --- .../HttpsTests.cs | 4 ++-- .../Listener/HttpsTests.cs | 4 ++-- .../Listener/RequestBodyTests.cs | 2 +- .../Listener/ResponseBodyTests.cs | 6 +++--- .../Listener/ResponseSendFileTests.cs | 4 ++-- .../Listener/SkipOffDomainAttribute.cs | 2 +- .../Listener/Utilities.cs | 2 +- ...crosoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj | 5 +++-- .../ResponseBodyTests.cs | 4 ++-- .../Microsoft.AspNetCore.Server.HttpSys.Tests.csproj | 3 ++- 10 files changed, 19 insertions(+), 17 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs index 6273a8fcdc..0a240f86fb 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs @@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private async Task SendRequestAsync(string uri, X509Certificate cert = null) { -#if NET451 +#if NET452 var handler = new WebRequestHandler(); #else var handler = new WinHttpHandler(); @@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private async Task SendRequestAsync(string uri, string upload) { -#if NET451 +#if NET452 var handler = new WebRequestHandler(); #else var handler = new WinHttpHandler(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs index c65ada8b93..d2c536ff41 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener private async Task SendRequestAsync(string uri, X509Certificate cert = null) { -#if NET451 +#if NET452 WebRequestHandler handler = new WebRequestHandler(); #else WinHttpHandler handler = new WinHttpHandler(); @@ -127,7 +127,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener private async Task SendRequestAsync(string uri, string upload) { -#if NET451 +#if NET452 WebRequestHandler handler = new WebRequestHandler(); #else WinHttpHandler handler = new WinHttpHandler(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index 3fca6084c9..e4ff4abaed 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Hello World", response); } } -#if NET451 +#if NET452 [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index fc281ee6d6..fa7705760e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -98,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 30 "; var stream = context.Response.Body; -#if NET451 +#if NET452 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); #else await stream.WriteAsync(new byte[10], 0, 10); @@ -282,7 +282,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET451 +#if NET452 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); @@ -311,7 +311,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET451 +#if NET452 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index df3f6ff75d..51967e9699 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET451 +#if NET452 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); @@ -391,7 +391,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET451 +#if NET452 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs index 7dc43fabcb..941425bdc3 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { try { -#if NET451 +#if NET452 return !string.IsNullOrEmpty(System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name); #endif } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs index a34cd20945..9bcf76d333 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { var win8Version = new Version(6, 2); -#if NET451 +#if NET452 IsWin8orLater = (Environment.OSVersion.Version >= win8Version); #else IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index a8aae54342..2d77749960 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -1,7 +1,8 @@  - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 @@ -10,7 +11,7 @@ - + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs index a1bac1ae70..199948dab8 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { httpContext.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = httpContext.Response.Body; -#if NET451 +#if NET452 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); #else await stream.WriteAsync(new byte[10], 0, 10); @@ -221,7 +221,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); } } -#if NET451 +#if NET452 [ConditionalFact] public async Task ResponseBody_BeginWrite_TriggersOnStarting() { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index b9e760080a..cc0b1a1396 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -1,7 +1,8 @@  - netcoreapp1.1;net451 + netcoreapp1.1;net452 + netcoreapp1.1 From 27d9b78fd2ead22bf2a3f2103d26004dfbcd2946 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 14 Feb 2017 16:03:55 -0800 Subject: [PATCH 453/597] Downgrade to stable packages --- build/common.props | 5 ++--- build/dependencies.props | 6 ++++++ .../Microsoft.AspNetCore.Server.HttpSys.csproj | 4 ++-- ...crosoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 build/dependencies.props diff --git a/build/common.props b/build/common.props index 2abfaa7306..609f4070e8 100644 --- a/build/common.props +++ b/build/common.props @@ -1,4 +1,5 @@ + @@ -8,8 +9,6 @@ $(MSBuildThisFileDirectory)Key.snk true true - 1.2.0-* - 1.6.2-* $(VersionSuffix)-$(BuildNumber) @@ -21,4 +20,4 @@ - \ No newline at end of file + diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..e704edaec0 --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,6 @@ + + + 1.6.1 + 4.3.0 + + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index 79b143c29b..33b9d8e595 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -15,7 +15,7 @@ - - + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 2d77749960..1ac989e98c 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -17,8 +17,8 @@ - - + + From fd82d0214ea9e1865a41858a2c6fa252e068c860 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 21 Feb 2017 09:16:54 -0800 Subject: [PATCH 454/597] Fix Theorys that should have been Facts. --- .../Listener/AuthenticationTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs index e3b7c9e5a4..9281b71817 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs @@ -169,7 +169,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalTheory] + [ConditionalFact] [SkipOffDomain] public async Task AuthTypes_RequireKerberosAuth_Success() { @@ -189,7 +189,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalTheory] + [ConditionalFact] [SkipOffDomain] public async Task MultipleAuthTypes_KerberosAllowAnonymousButSpecify401_ChallengesAdded() { From 76255bc7f45a48eaf15aacb144c2a5cffa033bde Mon Sep 17 00:00:00 2001 From: John Luo Date: Fri, 24 Feb 2017 14:57:48 -0800 Subject: [PATCH 455/597] Remove references to WebListener --- WebListener.sln => HttpSysServer.sln | 0 README.md | 2 +- src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs | 4 ++-- .../NativeInterop/TokenBindingUtil.cs | 2 +- .../RequestProcessing/Request.cs | 4 ++-- .../RequestProcessing/Response.cs | 2 +- .../StandardFeatureCollection.cs | 2 +- ...stenerExtensions.cs => WebHostBuilderHttpSysExtensions.cs} | 0 .../Listener/ResponseBodyTests.cs | 4 ++-- .../Listener/ResponseSendFileTests.cs | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) rename WebListener.sln => HttpSysServer.sln (100%) rename src/Microsoft.AspNetCore.Server.HttpSys/{WebHostBuilderWebListenerExtensions.cs => WebHostBuilderHttpSysExtensions.cs} (100%) diff --git a/WebListener.sln b/HttpSysServer.sln similarity index 100% rename from WebListener.sln rename to HttpSysServer.sln diff --git a/README.md b/README.md index 3f73ae3aaf..d97493f457 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ HttpSysServer | AppVeyor | Travis | | ---- | ---- -| [![AppVeyor](https://ci.appveyor.com/api/projects/status/413hlt87c3p24on8/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/WebListener/branch/dev) | [![Travis](https://travis-ci.org/aspnet/WebListener.svg?branch=dev)](https://travis-ci.org/aspnet/WebListener) | +| [![AppVeyor](https://ci.appveyor.com/api/projects/status/413hlt87c3p24on8/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/WebListener/branch/dev) | [![Travis](https://travis-ci.org/aspnet/HttpSysServer.svg?branch=dev)](https://travis-ci.org/aspnet/HttpSysServer) | This repo contains a web server for ASP.NET Core based on the Windows [Http Server API](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364510.aspx). diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index fd1dd9da04..9547a2ab3e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys IHttpResponseFeature, IHttpSendFileFeature, ITlsConnectionFeature, - // ITlsTokenBindingFeature, TODO: https://github.com/aspnet/WebListener/issues/231 + // ITlsTokenBindingFeature, TODO: https://github.com/aspnet/HttpSysServer/issues/231 IHttpBufferingFeature, IHttpRequestLifetimeFeature, IHttpAuthenticationFeature, @@ -332,7 +332,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { return Request.IsHttps ? this : null; } - /* TODO: https://github.com/aspnet/WebListener/issues/231 + /* TODO: https://github.com/aspnet/HttpSysServer/issues/231 byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId() => Request.GetProvidedTokenBindingId(); byte[] ITlsTokenBindingFeature.GetReferredTokenBindingId() => Request.GetReferredTokenBindingId(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs index 4c40acb935..ddb11c5240 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys /// /// Contains helpers for dealing with TLS token binding. /// - // TODO: https://github.com/aspnet/WebListener/issues/231 + // TODO: https://github.com/aspnet/HttpSysServer/issues/231 internal unsafe static class TokenBindingUtil { private static byte[] ExtractIdentifierBlob(TOKENBINDING_RESULT_DATA* pTokenBindingResultData) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 78ed055204..06a57f89ba 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private NativeRequestContext _nativeRequestContext; private X509Certificate2 _clientCert; - // TODO: https://github.com/aspnet/WebListener/issues/231 + // TODO: https://github.com/aspnet/HttpSysServer/issues/231 // private byte[] _providedTokenBindingId; // private byte[] _referredTokenBindingId; @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys User = nativeRequestContext.GetUser(); - // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/WebListener/issues/231 + // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/HttpSysServer/issues/231 // Finished directly accessing the HTTP_REQUEST structure. _nativeRequestContext.ReleasePins(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index 31846b6541..ec766cd8ae 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -375,7 +375,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { // A single write with the whole content-length. Http.Sys will set the content-length for us in this scenario. // If we don't remove it then range requests served from cache will have two. - // https://github.com/aspnet/WebListener/issues/167 + // https://github.com/aspnet/HttpSysServer/issues/167 ContentLength = null; } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs index 8af2ddb7ba..710286fc9d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { typeof(IHttpResponseFeature), _identityFunc }, { typeof(IHttpSendFileFeature), _identityFunc }, { typeof(ITlsConnectionFeature), ctx => ctx.GetTlsConnectionFeature() }, - // { typeof(ITlsTokenBindingFeature), ctx => ctx.GetTlsTokenBindingFeature() }, TODO: https://github.com/aspnet/WebListener/issues/231 + // { typeof(ITlsTokenBindingFeature), ctx => ctx.GetTlsTokenBindingFeature() }, TODO: https://github.com/aspnet/HttpSysServer/issues/231 { typeof(IHttpBufferingFeature), _identityFunc }, { typeof(IHttpRequestLifetimeFeature), _identityFunc }, { typeof(IHttpUpgradeFeature), _identityFunc }, diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderWebListenerExtensions.cs rename to src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index fa7705760e..18696e05dd 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -156,7 +156,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/WebListener/issues/263")] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { string address; @@ -510,7 +510,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/WebListener/issues/263")] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWriteAsync_WriteThrows() { string address; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index 51967e9699..7a2e861b13 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -504,7 +504,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "Tests hanging: https://github.com/aspnet/WebListener/issues/270")] + [ConditionalFact(Skip = "Tests hanging: https://github.com/aspnet/HttpSysServer/issues/270")] public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeSecondSend_SendThrows() { string address; From fcd06859232709d47b6ea98ac1812c6e0f2f5741 Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 28 Feb 2017 14:19:02 -0800 Subject: [PATCH 456/597] Reacting to HeaderUtilities renames --- .../RequestProcessing/HeaderCollection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs index 1eef943354..d0d6716486 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (rawValue.Count == 1 && !string.IsNullOrWhiteSpace(rawValue[0]) && - HeaderUtilities.TryParseInt64(new StringSegment(rawValue[0]).Trim(), out value)) + HeaderUtilities.TryParseNonNegativeInt64(new StringSegment(rawValue[0]).Trim(), out value)) { _contentLengthText = rawValue; _contentLength = value; @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative."); } - _contentLengthText = HeaderUtilities.FormatInt64(value.Value); + _contentLengthText = HeaderUtilities.FormatNonNegativeInt64(value.Value); this[HttpKnownHeaderNames.ContentLength] = _contentLengthText; _contentLength = value; } From 291355c2fe0810822a797cca8e069ea58f583eca Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Mar 2017 18:14:13 -0800 Subject: [PATCH 457/597] Change korebuild branch and fix argument forwarding in bootstrapper --- build.ps1 | 16 ++++++++-------- build.sh | 22 +++++++++++----------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build.ps1 b/build.ps1 index 0605b59c01..5bf0e2c113 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,6 +1,6 @@ $ErrorActionPreference = "Stop" -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) { while($true) { @@ -19,7 +19,7 @@ function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $ret Start-Sleep -Seconds 10 } - else + else { $exception = $_.Exception throw $exception @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP @@ -43,18 +43,18 @@ $buildFolder = ".build" $buildFile="$buildFolder\KoreBuild.ps1" if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - + Write-Host "Downloading KoreBuild from $koreBuildZip" + $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() New-Item -Path "$tempFolder" -Type directory | Out-Null $localZipFile="$tempFolder\korebuild.zip" - + DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - + New-Item -Path "$buildFolder" -Type directory | Out-Null copy-item "$tempFolder\**\build\*" $buildFolder -Recurse @@ -64,4 +64,4 @@ if (!(Test-Path $buildFolder)) { } } -&"$buildFile" $args \ No newline at end of file +&"$buildFile" @args diff --git a/build.sh b/build.sh index 07997d6c83..b0bcadb579 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/feature/msbuild.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi @@ -12,12 +12,12 @@ buildFile="$buildFolder/KoreBuild.sh" if test ! -d $buildFolder; then echo "Downloading KoreBuild from $koreBuildZip" - - tempFolder="/tmp/KoreBuild-$(uuidgen)" + + tempFolder="/tmp/KoreBuild-$(uuidgen)" mkdir $tempFolder - + localZipFile="$tempFolder/korebuild.zip" - + retries=6 until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) do @@ -29,18 +29,18 @@ if test ! -d $buildFolder; then echo "Waiting 10 seconds before retrying. Retries left: $retries" sleep 10s done - + unzip -q -d $tempFolder $localZipFile - + mkdir $buildFolder cp -r $tempFolder/**/build/** $buildFolder - + chmod +x $buildFile - + # Cleanup if test -d $tempFolder; then - rm -rf $tempFolder + rm -rf $tempFolder fi fi -$buildFile -r $repoFolder "$@" \ No newline at end of file +$buildFile -r $repoFolder "$@" From 71c1f371f8d29575e1119a47ca0a43e295cf8a66 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Mar 2017 18:25:39 -0800 Subject: [PATCH 458/597] Update AppVeyor and Travis settings --- .travis.yml | 4 ++-- appveyor.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0dfc19b8b2..5e68461e0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,10 +25,10 @@ branches: before_install: - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - - ./build.sh --quiet verify + - ./build.sh notifications: webhooks: secure: "XshregcmoXywFrrlIk7MLluUV2Pd8Z/VftrviVZjRL5+3akix2QnP15eT2E13yNtyS1yIc3lWfrVrLLf+H5bN9dUSzxIMNoJQ/S18F/AO5VD5ewd6pLC0uYhUcHdTRQuzjLGVPlt2suKpPllV2SsGlAdGatdCfj5zM6eOG31jaA=" on_success: always on_failure: always - on_start: always \ No newline at end of file + on_start: always diff --git a/appveyor.yml b/appveyor.yml index e31ecda1e0..3f828ce38e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,8 +7,8 @@ branches: - dev - /^(.*\/)?ci-.*$/ build_script: - - build.cmd verify + - ps: .\build.ps1 clone_depth: 1 test: off deploy: off -os: Visual Studio 2017 RC \ No newline at end of file +os: Visual Studio 2017 RC From aac4eebd799f39b7849b0cd1f01f7d813da63d09 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 27 Feb 2017 19:40:38 -0800 Subject: [PATCH 459/597] Direct address configuration #297 --- .../Properties/launchSettings.json | 3 +- samples/SelfHostServer/Startup.cs | 1 + .../Constants.cs | 1 + .../HttpSysOptions.cs | 2 - .../LogHelper.cs | 24 +++++++ .../MessagePump.cs | 67 ++++++++++++------- .../DummyApplication.cs | 3 + .../MessagePumpTests.cs | 61 +++++++++++++++++ .../ServerTests.cs | 2 +- 9 files changed, 133 insertions(+), 31 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs diff --git a/samples/SelfHostServer/Properties/launchSettings.json b/samples/SelfHostServer/Properties/launchSettings.json index f2eaeff38b..54fa816762 100644 --- a/samples/SelfHostServer/Properties/launchSettings.json +++ b/samples/SelfHostServer/Properties/launchSettings.json @@ -3,9 +3,8 @@ "SelfHostServer": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:8080/", + "launchUrl": "http://localhost:5000/", "environmentVariables": { - "ASPNETCORE_URLS": "http://localhost:8080/", "ASPNETCORE_ENVIRONMENT": "Development" } } diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index 4d2726587c..f6c0381b23 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -37,6 +37,7 @@ namespace SelfHostServer .UseStartup() .UseHttpSys(options => { + options.UrlPrefixes.Add("http://localhost:5000"); options.Authentication.Schemes = AuthenticationSchemes.None; options.Authentication.AllowAnonymous = true; }) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs index 83a80676fb..d7b5382d18 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs @@ -13,6 +13,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal const string Close = "close"; internal const string Zero = "0"; internal const string SchemeDelimiter = "://"; + internal const string DefaultServerAddress = "http://localhost:5000"; internal static Version V1_0 = new Version(1, 0); internal static Version V1_1 = new Version(1, 1); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index fe0c6d1d64..8b00e14e6a 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs b/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs index 6442e0842b..8c977074bf 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs @@ -31,6 +31,30 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + internal static void LogWarning(ILogger logger, string data) + { + if (logger == null) + { + Debug.WriteLine(data); + } + else + { + logger.LogWarning(data); + } + } + + internal static void LogDebug(ILogger logger, string data) + { + if (logger == null) + { + Debug.WriteLine(data); + } + else + { + logger.LogDebug(data); + } + } + internal static void LogDebug(ILogger logger, string location, string data) { if (logger == null) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 23921561c7..6fd6d3051a 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; @@ -16,8 +17,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys { internal class MessagePump : IServer { - private readonly HttpSysListener _listener; private readonly ILogger _logger; + private readonly HttpSysOptions _options; private IHttpApplication _application; @@ -42,23 +43,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys throw new ArgumentNullException(nameof(loggerFactory)); } - var optionsInstance = options.Value; - _listener = new HttpSysListener(optionsInstance, loggerFactory); + _options = options.Value; + Listener = new HttpSysListener(_options, loggerFactory); _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); Features = new FeatureCollection(); _serverAddresses = new ServerAddressesFeature(); Features.Set(_serverAddresses); _processRequest = new Action(ProcessRequestAsync); - _maxAccepts = optionsInstance.MaxAccepts; - EnableResponseCaching = optionsInstance.EnableResponseCaching; + _maxAccepts = _options.MaxAccepts; + EnableResponseCaching = _options.EnableResponseCaching; _shutdownSignal = new ManualResetEvent(false); } - internal HttpSysListener Listener - { - get { return _listener; } - } + internal HttpSysListener Listener { get; } internal bool EnableResponseCaching { get; set; } @@ -71,7 +69,37 @@ namespace Microsoft.AspNetCore.Server.HttpSys throw new ArgumentNullException(nameof(application)); } - ParseAddresses(_serverAddresses.Addresses, Listener); + var serverAdressesPresent = _serverAddresses.Addresses.Count > 0; + + if (_options.UrlPrefixes.Count > 0) + { + if (serverAdressesPresent) + { + LogHelper.LogWarning(_logger, $"Overriding address(es) '{string.Join(", ", _serverAddresses.Addresses)}'. " + + $"Binding to endpoints added to {nameof(HttpSysOptions.UrlPrefixes)} instead."); + + _serverAddresses.Addresses.Clear(); + + foreach (var prefix in _options.UrlPrefixes) + { + _serverAddresses.Addresses.Add(prefix.FullPrefix); + } + } + } + else if (serverAdressesPresent) + { + foreach (var value in _serverAddresses.Addresses) + { + Listener.Options.UrlPrefixes.Add(value); + } + } + else + { + LogHelper.LogDebug(_logger, $"No listening endpoints were configured. Binding to {Constants.DefaultServerAddress} by default."); + + _serverAddresses.Addresses.Add(Constants.DefaultServerAddress); + Listener.Options.UrlPrefixes.Add(Constants.DefaultServerAddress); + } // Can't call Start twice Contract.Assert(_application == null); @@ -80,12 +108,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _application = new ApplicationWrapper(application); - if (_listener.Options.UrlPrefixes.Count == 0) - { - throw new InvalidOperationException("No address prefixes were defined."); - } - - _listener.Start(); + Listener.Start(); ActivateRequestProcessingLimits(); } @@ -111,7 +134,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys RequestContext requestContext; try { - requestContext = await _listener.AcceptAsync().SupressContext(); + requestContext = await Listener.AcceptAsync().SupressContext(); } catch (Exception exception) { @@ -206,14 +229,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys context.Dispose(); } - private void ParseAddresses(ICollection addresses, HttpSysListener listener) - { - foreach (var value in addresses) - { - listener.Options.UrlPrefixes.Add(UrlPrefix.Create(value)); - } - } - public void Dispose() { _stopping = true; @@ -232,7 +247,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } // All requests are finished - _listener.Dispose(); + Listener.Dispose(); } private class ApplicationWrapper : IHttpApplication diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs index de88885137..4d1f273e4a 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -13,6 +14,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys { private readonly RequestDelegate _requestDelegate; + public DummyApplication() : this(context => TaskCache.CompletedTask) { } + public DummyApplication(RequestDelegate requestDelegate) { _requestDelegate = requestDelegate; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs new file mode 100644 index 0000000000..ccbc964607 --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs @@ -0,0 +1,61 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Linq; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Microsoft.AspNetCore.Server.HttpSys +{ + public class MessagePumpTests + { + [ConditionalTheory] + [InlineData("http://localhost:11001/")] + [InlineData("invalid address")] + [InlineData("")] + [InlineData(null)] + public void OverridingIServerAdressesFeatureWithDirectConfiguration_WarnsOnStart(string serverAddress) + { + var overrideAddress = "http://localhost:11002/"; + + using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + { + var serverAddressesFeature = server.Features.Get(); + serverAddressesFeature.Addresses.Add(serverAddress); + server.Listener.Options.UrlPrefixes.Add(overrideAddress); + + server.Start(new DummyApplication()); + + Assert.Equal(overrideAddress, serverAddressesFeature.Addresses.Single()); + } + } + + [ConditionalFact] + public void UseIServerAdressesFeature_WhenNoDirectConfiguration() + { + var serverAddress = "http://localhost:11001/"; + + using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + { + var serverAddressesFeature = server.Features.Get(); + serverAddressesFeature.Addresses.Add(serverAddress); + + server.Start(new DummyApplication()); + } + } + + [ConditionalFact] + public void UseDefaultAddress_WhenNoServerAddressAndNoDirectConfiguration() + { + using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + { + server.Start(new DummyApplication()); + + Assert.Equal(Constants.DefaultServerAddress, server.Features.Get().Addresses.Single()); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 2ae94400fa..2a6017a3b0 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -271,7 +271,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys using (server) { - server.Start(new DummyApplication(httpContext => Task.FromResult(0))); + server.Start(new DummyApplication()); string response = await SendRequestAsync(address); Assert.Equal(string.Empty, response); } From 50a9d6a0a114746d0e2388e0739fab6cdb8cd5aa Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Wed, 8 Mar 2017 13:20:20 -0800 Subject: [PATCH 460/597] Update AppVeyor link/badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d97493f457..b9c9f22edf 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ HttpSysServer | AppVeyor | Travis | | ---- | ---- -| [![AppVeyor](https://ci.appveyor.com/api/projects/status/413hlt87c3p24on8/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/WebListener/branch/dev) | [![Travis](https://travis-ci.org/aspnet/HttpSysServer.svg?branch=dev)](https://travis-ci.org/aspnet/HttpSysServer) | +| [![AppVeyor](https://ci.appveyor.com/api/projects/status/47fv9qoe862xlr25/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/HttpSysServer/branch/dev) | [![Travis](https://travis-ci.org/aspnet/HttpSysServer.svg?branch=dev)](https://travis-ci.org/aspnet/HttpSysServer) | This repo contains a web server for ASP.NET Core based on the Windows [Http Server API](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364510.aspx). From cd8d4f3ebf6fb4bb44fa3762fc42a997bea1616f Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 9 Mar 2017 11:19:58 -0800 Subject: [PATCH 461/597] Update .travis.yml (#323) --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5e68461e0a..f9d93ebd13 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,7 @@ addons: - libssl-dev - libunwind8 - zlib1g -mono: - - 4.0.5 +mono: none os: - linux - osx From bce80821c8b76a10882e5d2ad2a86ab05865ed75 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 14 Mar 2017 13:40:30 -0700 Subject: [PATCH 462/597] Update appveyor and travis settings --- .travis.yml | 1 - appveyor.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f9d93ebd13..79e1e46a09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ mono: none os: - linux - osx -osx_image: xcode7.3 branches: only: - master diff --git a/appveyor.yml b/appveyor.yml index 3f828ce38e..1041615c68 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,4 +11,4 @@ build_script: clone_depth: 1 test: off deploy: off -os: Visual Studio 2017 RC +os: Visual Studio 2017 From 5c4a132d71a8f22efcbe215472c00e9c167ad1bc Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 15 Mar 2017 14:24:15 -0700 Subject: [PATCH 463/597] Unify dependency versions to one file and remove workarounds --- .gitignore | 3 ++- build/dependencies.props | 5 ++++- samples/HotAddSample/HotAddSample.csproj | 12 +++++++++--- samples/SelfHostServer/SelfHostServer.csproj | 12 +++++++++--- .../SelfHostServer/runtimeconfig.template.json | 5 ----- .../Microsoft.AspNetCore.Server.HttpSys.csproj | 13 +++++++++---- ...tCore.Server.HttpSys.FunctionalTests.csproj | 18 ++++++++++++++---- ...soft.AspNetCore.Server.HttpSys.Tests.csproj | 14 +++++++++++--- 8 files changed, 58 insertions(+), 24 deletions(-) delete mode 100644 samples/SelfHostServer/runtimeconfig.template.json diff --git a/.gitignore b/.gitignore index c9c2ae767f..e51ec46f9b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,5 +26,6 @@ nuget.exe *.sln.ide project.lock.json /.vs +.vscode/ .build/ -.testPublish/ \ No newline at end of file +.testPublish/ diff --git a/build/dependencies.props b/build/dependencies.props index e704edaec0..5a4c06ce33 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,9 @@ - 1.6.1 + 1.2.0-* 4.3.0 + 1.6.1 + 15.0.0 + 2.2.0 diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index effb1b67e3..31de9ddc59 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -1,12 +1,18 @@  + + + net451;netcoreapp1.1 - - win7-x64 Exe + - + + + + + diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index effb1b67e3..31de9ddc59 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -1,12 +1,18 @@  + + + net451;netcoreapp1.1 - - win7-x64 Exe + - + + + + + diff --git a/samples/SelfHostServer/runtimeconfig.template.json b/samples/SelfHostServer/runtimeconfig.template.json deleted file mode 100644 index 12467a6df8..0000000000 --- a/samples/SelfHostServer/runtimeconfig.template.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "configProperties": { - "System.GC.Server": true - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index 33b9d8e595..e21a352f81 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -1,5 +1,7 @@  + + ASP.NET Core HTTP server that uses the Windows HTTP Server API. net451;netstandard1.3 @@ -8,14 +10,17 @@ true aspnetcore;weblistener;httpsys + - - - - + + + + + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 1ac989e98c..34d602e0a3 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -1,26 +1,36 @@  + + netcoreapp1.1;net452 netcoreapp1.1 + - - - - + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index cc0b1a1396..c681773b02 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -1,16 +1,24 @@  + + netcoreapp1.1;net452 netcoreapp1.1 + - - - + + + + + + + + From 066644654f08b3e65bd71eaa0b6d3711650f2f21 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 15 Mar 2017 14:46:30 -0700 Subject: [PATCH 464/597] Add server GC to samples --- samples/HotAddSample/HotAddSample.csproj | 1 + samples/SelfHostServer/SelfHostServer.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index 31de9ddc59..07c9191526 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -5,6 +5,7 @@ net451;netcoreapp1.1 Exe + true diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index 31de9ddc59..07c9191526 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -5,6 +5,7 @@ net451;netcoreapp1.1 Exe + true From a10d3eccbf08bbd7dc6cdd8e5be5952084ce630d Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 21 Mar 2017 12:00:05 -0700 Subject: [PATCH 465/597] Disable flaky tests --- .../Listener/ResponseBodyTests.cs | 6 +++--- .../ResponseCachingTests.cs | 2 +- .../ServerTests.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 18696e05dd..52f5994b74 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Aborts() { string address; @@ -325,7 +325,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public async Task ResponseBodyWriteExceptions_SecondWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -476,7 +476,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWrite_WriteThrows() { string address; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs index 6a2fe8c57d..8fa4448c26 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public async Task Caching_MaxAge_Cached() { var requestCount = 1; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 2a6017a3b0..10a356b487 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public void Server_MultipleOutstandingSyncRequests_Success() { int requestLimit = 10; From 8d610264386397c8493efa05cf10586f1c0f0198 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 21 Mar 2017 12:14:34 -0700 Subject: [PATCH 466/597] Update Travis to macOS Sierra [skip appveyor] --- .travis.yml | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 79e1e46a09..2a46104677 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,15 @@ language: csharp -sudo: required +sudo: false dist: trusty -addons: - apt: - packages: - - gettext - - libcurl4-openssl-dev - - libicu-dev - - libssl-dev - - libunwind8 - - zlib1g +env: + global: + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 mono: none os: - linux - osx +osx_image: xcode8.2 branches: only: - master @@ -24,9 +20,3 @@ before_install: - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi script: - ./build.sh -notifications: - webhooks: - secure: "XshregcmoXywFrrlIk7MLluUV2Pd8Z/VftrviVZjRL5+3akix2QnP15eT2E13yNtyS1yIc3lWfrVrLLf+H5bN9dUSzxIMNoJQ/S18F/AO5VD5ewd6pLC0uYhUcHdTRQuzjLGVPlt2suKpPllV2SsGlAdGatdCfj5zM6eOG31jaA=" - on_success: always - on_failure: always - on_start: always From d103bdb1ba80574c99502d1fb4709ae669bed837 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 1 Mar 2017 16:00:18 -0800 Subject: [PATCH 467/597] #287 Do not include an auth display name --- .../AuthenticationHandler.cs | 1 - .../AuthenticationTests.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs index 81c030e30e..b47adc17d0 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs @@ -117,7 +117,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys return new Dictionary() { { "AuthenticationScheme", authenticationScheme }, - { "DisplayName", "Windows:" + authenticationScheme }, }; } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index a5ee320541..358ac346db 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -192,7 +192,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(1, resultList.Count()); var result = resultList.First(); Assert.Equal(authType.ToString(), result.AuthenticationScheme); - Assert.Equal("Windows:" + authType.ToString(), result.DisplayName); + Assert.Null(result.DisplayName); } return Task.FromResult(0); From c328e22699627d337dfa89fe20df6a93f455cb67 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 1 Mar 2017 16:08:42 -0800 Subject: [PATCH 468/597] #306 Consistently use WindowsPrincipal --- .../AuthenticationHandler.cs | 5 +++-- .../RequestProcessing/NativeRequestContext.cs | 5 +++-- .../RequestProcessing/Request.cs | 3 ++- .../RequestProcessing/RequestContext.cs | 3 ++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs index b47adc17d0..2daad5bb43 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Security.Claims; +using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Extensions.Internal; @@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public Task AuthenticateAsync(AuthenticateContext context) { - var identity = (ClaimsIdentity)_requestContext.User?.Identity; + var identity = _requestContext.User?.Identity; foreach (var authType in ListEnabledAuthSchemes()) { @@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (identity != null && identity.IsAuthenticated && string.Equals(authScheme, identity.AuthenticationType, StringComparison.Ordinal)) { - context.Authenticated(new ClaimsPrincipal(identity), properties: null, description: GetDescription(authScheme)); + context.Authenticated(_requestContext.User, properties: null, description: null); } else { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs index 9a26984742..a155b59363 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs @@ -212,7 +212,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys return false; } - internal ClaimsPrincipal GetUser() + internal WindowsPrincipal GetUser() { var requestInfo = NativeRequestV2->pRequestInfo; var infoCount = NativeRequestV2->RequestInfoCount; @@ -228,7 +228,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys GetAuthTypeFromRequest(info->pInfo->AuthType).ToString())); } } - return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated + + return new WindowsPrincipal(WindowsIdentity.GetAnonymous()); // Anonymous / !IsAuthenticated } private static AuthenticationSchemes GetAuthTypeFromRequest(HttpApi.HTTP_REQUEST_AUTH_TYPE input) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 06a57f89ba..d8a03d2cf9 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -7,6 +7,7 @@ using System.IO; using System.Net; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; @@ -214,7 +215,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys // HTTP.Sys allows you to upgrade anything to opaque unless content-length > 0 or chunked are specified. internal bool IsUpgradable => !HasEntityBody && ComNetOS.IsWin8orLater; - internal ClaimsPrincipal User { get; } + internal WindowsPrincipal User { get; } // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index 428bf2a18c..22b3ca6b13 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.IO; using System.Security.Authentication.ExtendedProtection; using System.Security.Claims; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -39,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public Response Response { get; } - public ClaimsPrincipal User => Request.User; + public WindowsPrincipal User => Request.User; public CancellationToken DisconnectToken { From 32bc9a57c94525326cd8c15c580db884c790d294 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 22 Mar 2017 14:08:50 -0700 Subject: [PATCH 469/597] #317 Dispose WindowsIdentity --- .../RequestProcessing/NativeRequestContext.cs | 10 ++++++++-- .../RequestProcessing/Request.cs | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs index a155b59363..7bcbb258b5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs @@ -224,8 +224,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys && info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth && info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) { - return new WindowsPrincipal(new WindowsIdentity(info->pInfo->AccessToken, - GetAuthTypeFromRequest(info->pInfo->AuthType).ToString())); + // Duplicates AccessToken + var identity = new WindowsIdentity(info->pInfo->AccessToken, + GetAuthTypeFromRequest(info->pInfo->AuthType).ToString()); + + // Close the original + UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(info->pInfo->AccessToken); + + return new WindowsPrincipal(identity); } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index d8a03d2cf9..043790f8e0 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -302,6 +302,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys // TODO: Verbose log _isDisposed = true; _nativeRequestContext.Dispose(); + (User?.Identity as WindowsIdentity)?.Dispose(); if (_nativeStream != null) { _nativeStream.Dispose(); From 60f456dc7e1ed4e10bb305ba53dce0057fb9193c Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 22 Mar 2017 14:09:06 -0700 Subject: [PATCH 470/597] Retarget test app --- samples/TestClient/App.config | 6 +++--- samples/TestClient/TestClient.csproj | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/samples/TestClient/App.config b/samples/TestClient/App.config index 8e15646352..2d2a12d81b 100644 --- a/samples/TestClient/App.config +++ b/samples/TestClient/App.config @@ -1,6 +1,6 @@ - + - + - \ No newline at end of file + diff --git a/samples/TestClient/TestClient.csproj b/samples/TestClient/TestClient.csproj index eb38a21555..781a187052 100644 --- a/samples/TestClient/TestClient.csproj +++ b/samples/TestClient/TestClient.csproj @@ -1,5 +1,5 @@  - + Debug @@ -9,10 +9,11 @@ Properties TestClient TestClient - v4.5 + v4.6 512 ..\..\ true + AnyCPU From 0586fd136f0a4238b8b0e545d147ff8a60e3d897 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Thu, 23 Mar 2017 00:28:49 -0700 Subject: [PATCH 471/597] Converted samples and test projects to run on netcoreapp2.0 --- build/dependencies.props | 1 + samples/HotAddSample/HotAddSample.csproj | 2 +- samples/SelfHostServer/SelfHostServer.csproj | 2 +- .../HttpsTests.cs | 8 ++++++-- .../Listener/HttpsTests.cs | 8 ++++++-- .../Listener/RequestBodyTests.cs | 3 +++ .../Listener/ResponseBodyTests.cs | 15 +++++++++++++-- .../Listener/ResponseHeaderTests.cs | 12 ++++++++---- .../Listener/ResponseSendFileTests.cs | 6 ++++++ .../Listener/ServerTests.cs | 5 ++++- .../Listener/SkipOffDomainAttribute.cs | 3 +++ .../Listener/Utilities.cs | 4 +++- ...pNetCore.Server.HttpSys.FunctionalTests.csproj | 6 +++--- .../RequestBodyTests.cs | 5 ++++- .../ResponseBodyTests.cs | 7 ++++++- .../ResponseHeaderTests.cs | 12 ++++++++---- ...crosoft.AspNetCore.Server.HttpSys.Tests.csproj | 4 ++-- 17 files changed, 78 insertions(+), 25 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5a4c06ce33..12a50aa67f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,6 +3,7 @@ 1.2.0-* 4.3.0 1.6.1 + 2.0.0-* 15.0.0 2.2.0 diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index 07c9191526..10f656a63b 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp1.1 + net451;netcoreapp2.0 Exe true diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index 07c9191526..10f656a63b 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -3,7 +3,7 @@ - net451;netcoreapp1.1 + net451;netcoreapp2.0 Exe true diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs index 0a240f86fb..b0bcb6e612 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs @@ -104,8 +104,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys { #if NET452 var handler = new WebRequestHandler(); -#else +#elif NETCOREAPP2_0 var handler = new WinHttpHandler(); +#else +#error Target framework needs to be updated #endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; if (cert != null) @@ -122,8 +124,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys { #if NET452 var handler = new WebRequestHandler(); -#else +#elif NETCOREAPP2_0 var handler = new WinHttpHandler(); +#else +#error Target framework needs to be updated #endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; using (HttpClient client = new HttpClient(handler)) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs index d2c536ff41..b7a05b5e1f 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs @@ -111,8 +111,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { #if NET452 WebRequestHandler handler = new WebRequestHandler(); -#else +#elif NETCOREAPP2_0 WinHttpHandler handler = new WinHttpHandler(); +#else +#error Target framework needs to be updated #endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; if (cert != null) @@ -129,8 +131,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { #if NET452 WebRequestHandler handler = new WebRequestHandler(); -#else +#elif NETCOREAPP2_0 WinHttpHandler handler = new WinHttpHandler(); +#else +#error Target framework needs to be updated #endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; using (HttpClient client = new HttpClient(handler)) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index e4ff4abaed..1c4da2210f 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -72,6 +72,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Hello World", response); } } +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif [ConditionalFact] diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 52f5994b74..d129e7fbfc 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -100,8 +100,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var stream = context.Response.Body; #if NET452 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); -#else +#elif NETCOREAPP2_0 await stream.WriteAsync(new byte[10], 0, 10); +#else +#error Target framework needs to be updated #endif stream.Write(new byte[10], 0, 10); await stream.WriteAsync(new byte[10], 0, 10); @@ -129,11 +131,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#if !NETCOREAPP1_1 +#if NET452 // HttpClient retries the request because it didn't get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif await Assert.ThrowsAsync(() => responseTask); } @@ -291,6 +296,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif await Assert.ThrowsAsync(() => responseTask); } @@ -320,6 +328,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif await Assert.ThrowsAsync(() => responseTask); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 83e9b126ef..4b0c5b8f48 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -221,10 +221,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); -#else +#elif NET452 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); +#else +#error Target framework needs to be updated #endif } } @@ -250,10 +252,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); -#else +#elif NET452 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); +#else +#error Target framework needs to be updated #endif } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index 7a2e861b13..2172157489 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -371,6 +371,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif await Assert.ThrowsAsync(() => responseTask); } @@ -400,6 +403,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif await Assert.ThrowsAsync(() => responseTask); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index 6400b7f202..fa6a81246e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -186,10 +186,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); -#if !NETCOREAPP1_1 +#if NET452 // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Abort(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif await Assert.ThrowsAsync(() => responseTask); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs index 941425bdc3..75b956a1b2 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs @@ -20,6 +20,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { #if NET452 return !string.IsNullOrEmpty(System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif } catch diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs index 9bcf76d333..6b35ade3df 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs @@ -28,8 +28,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener #if NET452 IsWin8orLater = (Environment.OSVersion.Version >= win8Version); -#else +#elif NETCOREAPP2_0 IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version); +#else +#error Target framework needs to be updated #endif } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 34d602e0a3..e717078d1b 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 @@ -24,7 +24,7 @@ - + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs index f2da4d3baf..790434bc33 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Hello World", response); } } -#if !NETCOREAPP1_1 +#if NET452 [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { @@ -68,6 +68,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Hello World", response); } } +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif [ConditionalFact] diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs index 199948dab8..a55c2aa1d0 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs @@ -89,8 +89,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys Stream stream = httpContext.Response.Body; #if NET452 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); -#else +#elif NETCOREAPP2_0 await stream.WriteAsync(new byte[10], 0, 10); +#else +#error Target framework needs to be updated #endif stream.Write(new byte[10], 0, 10); await stream.WriteAsync(new byte[10], 0, 10); @@ -249,6 +251,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); } } +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated #endif [ConditionalFact] public async Task ResponseBody_WriteAsync_TriggersOnStarting() diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index 3631fc769b..cd041e15c1 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -81,10 +81,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); -#else +#elif NET452 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); +#else +#error Target framework needs to be updated #endif } } @@ -109,10 +111,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP1_1 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); -#else +#elif NET452 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); +#else +#error Target framework needs to be updated #endif } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index c681773b02..cd0c882e6f 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -3,8 +3,8 @@ - netcoreapp1.1;net452 - netcoreapp1.1 + netcoreapp2.0;net452 + netcoreapp2.0 From 53946e98566c1bf850676e5e7d8d13e66ab60854 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 13 Mar 2017 08:46:14 -0700 Subject: [PATCH 472/597] Remove net451 as a cross-compile target --- HttpSysServer.sln | 3 +- build/dependencies.props | 1 + samples/HotAddSample/HotAddSample.csproj | 5 +- samples/SelfHostServer/SelfHostServer.csproj | 5 +- ...Microsoft.AspNetCore.Server.HttpSys.csproj | 4 +- .../NativeInterop/AddressFamily.cs | 2 +- .../Overlapped/DeferredDisposableLifetime.cs | 88 ----------- .../Overlapped/IDeferredDisposable.cs | 13 -- .../Overlapped/PreAllocatedOverlapped.cs | 53 ------- .../Overlapped/ThreadPoolBoundHandle.cs | 146 ------------------ .../ThreadPoolBoundHandleOverlapped.cs | 41 ----- .../AuthenticationTests.cs | 1 - .../HttpsTests.cs | 4 +- .../Listener/HttpsTests.cs | 4 +- .../Listener/RequestBodyTests.cs | 2 +- .../Listener/ResponseBodyTests.cs | 8 +- .../Listener/ResponseHeaderTests.cs | 4 +- .../Listener/ResponseSendFileTests.cs | 4 +- .../Listener/ServerTests.cs | 2 +- .../Listener/SkipOffDomainAttribute.cs | 2 +- .../Listener/Utilities.cs | 4 +- ...Core.Server.HttpSys.FunctionalTests.csproj | 5 +- .../RequestBodyTests.cs | 2 +- .../ResponseBodyTests.cs | 4 +- .../ResponseHeaderTests.cs | 4 +- ...oft.AspNetCore.Server.HttpSys.Tests.csproj | 5 +- 26 files changed, 33 insertions(+), 383 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/DeferredDisposableLifetime.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/IDeferredDisposable.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/PreAllocatedOverlapped.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandle.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandleOverlapped.cs diff --git a/HttpSysServer.sln b/HttpSysServer.sln index de17b49c97..0663cc30a2 100644 --- a/HttpSysServer.sln +++ b/HttpSysServer.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26202.1 +VisualStudioVersion = 15.0.26228.9 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{99D5E5F3-88F5-4CCF-8D8C-717C8925DF09}" EndProject @@ -34,6 +34,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{85914BA9-4168-48C5-9C3F-E2E8B1479A6E}" ProjectSection(SolutionItems) = preProject build\common.props = build\common.props + build\dependencies.props = build\dependencies.props build\Key.snk = build\Key.snk EndProjectSection EndProject diff --git a/build/dependencies.props b/build/dependencies.props index 12a50aa67f..dc20c228e8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,6 +4,7 @@ 4.3.0 1.6.1 2.0.0-* + 4.3.1 15.0.0 2.2.0 diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index 10f656a63b..e9223fff1b 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -3,16 +3,13 @@ - net451;netcoreapp2.0 + net46;netcoreapp2.0 Exe true - - - diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index 10f656a63b..e9223fff1b 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -3,16 +3,13 @@ - net451;netcoreapp2.0 + net46;netcoreapp2.0 Exe true - - - diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index e21a352f81..1f01f022d7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -4,7 +4,7 @@ ASP.NET Core HTTP server that uses the Windows HTTP Server API. - net451;netstandard1.3 + net46;netstandard1.3 $(NoWarn);CS1591 true true @@ -16,11 +16,11 @@ + - diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs index a9938a3a70..239d36533e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { -#if NET451 +#if NET46 /// /// /// Specifies the address families that an instance of the diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/DeferredDisposableLifetime.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/DeferredDisposableLifetime.cs deleted file mode 100644 index 8790de29ab..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/DeferredDisposableLifetime.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. -using System; -namespace System.Threading -{ - internal struct DeferredDisposableLifetime where T : class, IDeferredDisposable - { - private int _count; - public bool AddRef(T obj) - { - while (true) - { - int num = Volatile.Read(ref this._count); - if (num < 0) - { - break; - } - int num2 = checked(num + 1); - if (Interlocked.CompareExchange(ref this._count, num2, num) == num) - { - return true; - } - } - throw new ObjectDisposedException(typeof(T).ToString()); - } - public void Release(T obj) - { - int num2; - int num3; - while (true) - { - int num = Volatile.Read(ref this._count); - if (num > 0) - { - num2 = num - 1; - if (Interlocked.CompareExchange(ref this._count, num2, num) == num) - { - break; - } - } - else - { - num3 = num + 1; - if (Interlocked.CompareExchange(ref this._count, num3, num) == num) - { - goto Block_3; - } - } - } - if (num2 == 0) - { - obj.OnFinalRelease(false); - } - return; - Block_3: - if (num3 == -1) - { - obj.OnFinalRelease(true); - } - } - public void Dispose(T obj) - { - int num2; - while (true) - { - int num = Volatile.Read(ref this._count); - if (num < 0) - { - break; - } - num2 = -1 - num; - if (Interlocked.CompareExchange(ref this._count, num2, num) == num) - { - goto Block_1; - } - } - return; - Block_1: - if (num2 == -1) - { - obj.OnFinalRelease(true); - } - } - } -} -#endif \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/IDeferredDisposable.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/IDeferredDisposable.cs deleted file mode 100644 index bc1ed90211..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/IDeferredDisposable.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. -using System; -namespace System.Threading -{ - internal interface IDeferredDisposable - { - void OnFinalRelease(bool disposed); - } -} -#endif \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/PreAllocatedOverlapped.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/PreAllocatedOverlapped.cs deleted file mode 100644 index 92530f048f..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/PreAllocatedOverlapped.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. -using System; -namespace System.Threading -{ - internal sealed class PreAllocatedOverlapped : IDisposable, IDeferredDisposable - { - internal readonly ThreadPoolBoundHandleOverlapped _overlapped; - private DeferredDisposableLifetime _lifetime; - public PreAllocatedOverlapped(IOCompletionCallback callback, object state, object pinData) - { - if (callback == null) - { - throw new ArgumentNullException("callback"); - } - this._overlapped = new ThreadPoolBoundHandleOverlapped(callback, state, pinData, this); - } - internal bool AddRef() - { - return this._lifetime.AddRef(this); - } - internal void Release() - { - this._lifetime.Release(this); - } - public void Dispose() - { - this._lifetime.Dispose(this); - GC.SuppressFinalize(this); - } - ~PreAllocatedOverlapped() - { - if (!Environment.HasShutdownStarted) - { - this.Dispose(); - } - } - unsafe void IDeferredDisposable.OnFinalRelease(bool disposed) - { - if (disposed) - { - Overlapped.Free(this._overlapped._nativeOverlapped); - return; - } - this._overlapped._boundHandle = null; - this._overlapped._completed = false; - *this._overlapped._nativeOverlapped = default(NativeOverlapped); - } - } -} -#endif \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandle.cs deleted file mode 100644 index bea558e342..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandle.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. -using System; -using System.Runtime.InteropServices; -namespace System.Threading -{ - internal sealed class ThreadPoolBoundHandle : IDisposable - { - private readonly SafeHandle _handle; - private bool _isDisposed; - public SafeHandle Handle - { - get - { - return this._handle; - } - } - private ThreadPoolBoundHandle(SafeHandle handle) - { - this._handle = handle; - } - public static ThreadPoolBoundHandle BindHandle(SafeHandle handle) - { - if (handle == null) - { - throw new ArgumentNullException("handle"); - } - if (handle.IsClosed || handle.IsInvalid) - { - throw new ArgumentException("Invalid Handle", "handle"); - } - try - { - ThreadPool.BindHandle(handle); - } - catch (Exception expr_38) - { - if (expr_38.HResult == -2147024890) - { - throw new ArgumentException("Invalid Handle", "handle"); - } - if (expr_38.HResult == -2147024809) - { - throw new ArgumentException("Already Bound", "handle"); - } - throw; - } - return new ThreadPoolBoundHandle(handle); - } - - public unsafe NativeOverlapped* AllocateNativeOverlapped(IOCompletionCallback callback, object state, object pinData) - { - if (callback == null) - { - throw new ArgumentNullException("callback"); - } - this.EnsureNotDisposed(); - return new ThreadPoolBoundHandleOverlapped(callback, state, pinData, null) - { - _boundHandle = this - }._nativeOverlapped; - } - - public unsafe NativeOverlapped* AllocateNativeOverlapped(PreAllocatedOverlapped preAllocated) - { - if (preAllocated == null) - { - throw new ArgumentNullException("preAllocated"); - } - this.EnsureNotDisposed(); - preAllocated.AddRef(); - NativeOverlapped* nativeOverlapped; - try - { - ThreadPoolBoundHandleOverlapped expr_21 = preAllocated._overlapped; - if (expr_21._boundHandle != null) - { - throw new ArgumentException("Already Allocated", "preAllocated"); - } - expr_21._boundHandle = this; - nativeOverlapped = expr_21._nativeOverlapped; - } - catch - { - preAllocated.Release(); - throw; - } - return nativeOverlapped; - } - - public unsafe void FreeNativeOverlapped(NativeOverlapped* overlapped) - { - if (overlapped == null) - { - throw new ArgumentNullException("overlapped"); - } - ThreadPoolBoundHandleOverlapped overlappedWrapper = ThreadPoolBoundHandle.GetOverlappedWrapper(overlapped, this); - if (overlappedWrapper._boundHandle != this) - { - throw new ArgumentException("Wrong bound handle", "overlapped"); - } - if (overlappedWrapper._preAllocated != null) - { - overlappedWrapper._preAllocated.Release(); - return; - } - Overlapped.Free(overlapped); - } - - public unsafe static object GetNativeOverlappedState(NativeOverlapped* overlapped) - { - if (overlapped == null) - { - throw new ArgumentNullException("overlapped"); - } - return ThreadPoolBoundHandle.GetOverlappedWrapper(overlapped, null)._userState; - } - private unsafe static ThreadPoolBoundHandleOverlapped GetOverlappedWrapper(NativeOverlapped* overlapped, ThreadPoolBoundHandle expectedBoundHandle) - { - ThreadPoolBoundHandleOverlapped result; - try - { - result = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(overlapped); - } - catch (NullReferenceException ex) - { - throw new ArgumentException("Already freed", "overlapped", ex); - } - return result; - } - public void Dispose() - { - this._isDisposed = true; - } - private void EnsureNotDisposed() - { - if (this._isDisposed) - { - throw new ObjectDisposedException(base.GetType().ToString()); - } - } - } -} -#endif \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandleOverlapped.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandleOverlapped.cs deleted file mode 100644 index 1ec336af68..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Overlapped/ThreadPoolBoundHandleOverlapped.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if !NETSTANDARD1_3 // TODO: Temp copy. Remove once we target net46. -using System; -namespace System.Threading -{ - internal sealed class ThreadPoolBoundHandleOverlapped : Overlapped - { - private readonly IOCompletionCallback _userCallback; - internal readonly object _userState; - internal PreAllocatedOverlapped _preAllocated; - internal unsafe NativeOverlapped* _nativeOverlapped; - internal ThreadPoolBoundHandle _boundHandle; - internal bool _completed; - public unsafe ThreadPoolBoundHandleOverlapped(IOCompletionCallback callback, object state, object pinData, PreAllocatedOverlapped preAllocated) - { - this._userCallback = callback; - this._userState = state; - this._preAllocated = preAllocated; - this._nativeOverlapped = base.Pack(new IOCompletionCallback(ThreadPoolBoundHandleOverlapped.CompletionCallback), pinData); - this._nativeOverlapped->OffsetLow = 0; - this._nativeOverlapped->OffsetHigh = 0; - } - private unsafe static void CompletionCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) - { - ThreadPoolBoundHandleOverlapped expr_0B = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(nativeOverlapped); - if (expr_0B._completed) - { - throw new InvalidOperationException("Native Overlapped reused"); - } - expr_0B._completed = true; - if (expr_0B._boundHandle == null) - { - throw new InvalidOperationException("Already freed"); - } - expr_0B._userCallback.Invoke(errorCode, numBytes, nativeOverlapped); - } - } -} -#endif \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index 358ac346db..c5cddc6e6d 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -9,7 +9,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -using AuthenticationSchemes = Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs index b0bcb6e612..d42936325d 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs @@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private async Task SendRequestAsync(string uri, X509Certificate cert = null) { -#if NET452 +#if NET46 var handler = new WebRequestHandler(); #elif NETCOREAPP2_0 var handler = new WinHttpHandler(); @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private async Task SendRequestAsync(string uri, string upload) { -#if NET452 +#if NET46 var handler = new WebRequestHandler(); #elif NETCOREAPP2_0 var handler = new WinHttpHandler(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs index b7a05b5e1f..9075e8e831 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener private async Task SendRequestAsync(string uri, X509Certificate cert = null) { -#if NET452 +#if NET46 WebRequestHandler handler = new WebRequestHandler(); #elif NETCOREAPP2_0 WinHttpHandler handler = new WinHttpHandler(); @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener private async Task SendRequestAsync(string uri, string upload) { -#if NET452 +#if NET46 WebRequestHandler handler = new WebRequestHandler(); #elif NETCOREAPP2_0 WinHttpHandler handler = new WinHttpHandler(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index 1c4da2210f..78a37d1af7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Hello World", response); } } -#if NET452 +#if NET46 [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index d129e7fbfc..94cafa7255 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -98,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 30 "; var stream = context.Response.Body; -#if NET452 +#if NET46 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); #elif NETCOREAPP2_0 await stream.WriteAsync(new byte[10], 0, 10); @@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#if NET452 +#if NET46 // HttpClient retries the request because it didn't get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; @@ -287,7 +287,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET452 +#if NET46 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); @@ -319,7 +319,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET452 +#if NET46 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 4b0c5b8f48..1da87eab2c 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); #if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); -#elif NET452 +#elif NET46 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); #else #error Target framework needs to be updated @@ -254,7 +254,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); #if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); -#elif NET452 +#elif NET46 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); #else #error Target framework needs to be updated diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index 2172157489..b025dff302 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET452 +#if NET46 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); @@ -394,7 +394,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET452 +#if NET46 // .NET 4.5 HttpClient automatically retries a request if it does not get a response. context = await server.AcceptAsync(Utilities.DefaultTimeout); cts = new CancellationTokenSource(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index fa6a81246e..6633fbbaca 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); -#if NET452 +#if NET46 // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Abort(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs index 75b956a1b2..f74046ec1d 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { try { -#if NET452 +#if NET46 return !string.IsNullOrEmpty(System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name); #elif NETCOREAPP2_0 #else diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs index 6b35ade3df..8a5d5d9a55 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; @@ -25,8 +24,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener static Utilities() { var win8Version = new Version(6, 2); - -#if NET452 +#if NET46 IsWin8orLater = (Environment.OSVersion.Version >= win8Version); #elif NETCOREAPP2_0 IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index e717078d1b..809f73775c 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -3,7 +3,7 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 @@ -16,9 +16,10 @@ + - + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs index 790434bc33..b55b3f9d50 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Hello World", response); } } -#if NET452 +#if NET46 [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs index a55c2aa1d0..f35d322add 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { httpContext.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = httpContext.Response.Body; -#if NET452 +#if NET46 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); #elif NETCOREAPP2_0 await stream.WriteAsync(new byte[10], 0, 10); @@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); } } -#if NET452 +#if NET46 [ConditionalFact] public async Task ResponseBody_BeginWrite_TriggersOnStarting() { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index cd041e15c1..cc9f5ad87c 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); #if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); -#elif NET452 +#elif NET46 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); #else #error Target framework needs to be updated @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); #if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); -#elif NET452 +#elif NET46 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); #else #error Target framework needs to be updated diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index cd0c882e6f..cef136bb6b 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -3,15 +3,12 @@ - netcoreapp2.0;net452 + netcoreapp2.0;net46 netcoreapp2.0 - - - From e746e8b36cff918f8e79856e670ececabaab12c8 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Thu, 23 Mar 2017 20:40:02 -0700 Subject: [PATCH 473/597] Disable test See #263 --- .../Listener/ResponseBodyTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 94cafa7255..072e2a25c4 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -358,7 +358,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public async Task ResponseBody_SecondWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; From 5f161fb51f7cf5d21a4fc480be9ab0bd581d28a4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Mar 2017 11:30:34 -0700 Subject: [PATCH 474/597] Updating to 2.0.0 Internal.AspNetCore.Sdk --- build/common.props | 2 +- build/dependencies.props | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build/common.props b/build/common.props index 609f4070e8..5e264337e2 100644 --- a/build/common.props +++ b/build/common.props @@ -13,7 +13,7 @@ - + diff --git a/build/dependencies.props b/build/dependencies.props index dc20c228e8..88715db994 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,10 +2,11 @@ 1.2.0-* 4.3.0 + 2.0.0-* 1.6.1 2.0.0-* 4.3.1 15.0.0 2.2.0 - + \ No newline at end of file From fd27c7fcc68e0687440a36147cd4ecbbf06c9627 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 3 Apr 2017 21:41:10 -0700 Subject: [PATCH 475/597] Updating versions to 2.0.0-preview1 --- build/dependencies.props | 2 +- version.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 88715db994..2867efab1d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 1.2.0-* + 2.0.0-* 4.3.0 2.0.0-* 1.6.1 diff --git a/version.props b/version.props index 38c93687ab..10a1c898f3 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 1.2.0 + 2.0.0 preview1 \ No newline at end of file From bc003985c602d075c73531c48ed9d33c3525371c Mon Sep 17 00:00:00 2001 From: John Luo Date: Sun, 2 Apr 2017 18:04:22 -0700 Subject: [PATCH 476/597] React to addition of PreferHostingUrls --- .../MessagePump.cs | 33 +++++++---- .../MessagePumpTests.cs | 57 +++++++++++++++++++ 2 files changed, 80 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 6fd6d3051a..01b8d831e8 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -2,11 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; @@ -69,24 +67,39 @@ namespace Microsoft.AspNetCore.Server.HttpSys throw new ArgumentNullException(nameof(application)); } - var serverAdressesPresent = _serverAddresses.Addresses.Count > 0; + var hostingUrlsPresent = _serverAddresses.Addresses.Count > 0; - if (_options.UrlPrefixes.Count > 0) + if (_serverAddresses.PreferHostingUrls && hostingUrlsPresent) { - if (serverAdressesPresent) + if (_options.UrlPrefixes.Count > 0) + { + LogHelper.LogWarning(_logger, $"Overriding endpoints added to {nameof(HttpSysOptions.UrlPrefixes)} since {nameof(IServerAddressesFeature.PreferHostingUrls)} is set to true." + + $" Binding to address(es) '{string.Join(", ", _serverAddresses.Addresses)}' instead. "); + + Listener.Options.UrlPrefixes.Clear(); + } + + foreach (var value in _serverAddresses.Addresses) + { + Listener.Options.UrlPrefixes.Add(value); + } + } + else if (_options.UrlPrefixes.Count > 0) + { + if (hostingUrlsPresent) { LogHelper.LogWarning(_logger, $"Overriding address(es) '{string.Join(", ", _serverAddresses.Addresses)}'. " + $"Binding to endpoints added to {nameof(HttpSysOptions.UrlPrefixes)} instead."); _serverAddresses.Addresses.Clear(); + } - foreach (var prefix in _options.UrlPrefixes) - { - _serverAddresses.Addresses.Add(prefix.FullPrefix); - } + foreach (var prefix in _options.UrlPrefixes) + { + _serverAddresses.Addresses.Add(prefix.FullPrefix); } } - else if (serverAdressesPresent) + else if (hostingUrlsPresent) { foreach (var value in _serverAddresses.Addresses) { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs index ccbc964607..48913a746f 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs @@ -12,6 +12,63 @@ namespace Microsoft.AspNetCore.Server.HttpSys { public class MessagePumpTests { + [ConditionalFact] + public void OverridingDirectConfigurationWithIServerAddressesFeatureSucceeds() + { + var serverAddress = "http://localhost:11001/"; + var overrideAddress = "http://localhost:11002/"; + + using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + { + var serverAddressesFeature = server.Features.Get(); + serverAddressesFeature.Addresses.Add(overrideAddress); + serverAddressesFeature.PreferHostingUrls = true; + server.Listener.Options.UrlPrefixes.Add(serverAddress); + + server.Start(new DummyApplication()); + + Assert.Equal(overrideAddress, serverAddressesFeature.Addresses.Single()); + } + } + + [ConditionalTheory] + [InlineData("http://localhost:11001/")] + [InlineData("invalid address")] + [InlineData("")] + [InlineData(null)] + public void DoesNotOverrideDirectConfigurationWithIServerAddressesFeature_IfPreferHostinUrlsFalse(string overrideAddress) + { + var serverAddress = "http://localhost:11002/"; + + using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + { + var serverAddressesFeature = server.Features.Get(); + serverAddressesFeature.Addresses.Add(overrideAddress); + server.Listener.Options.UrlPrefixes.Add(serverAddress); + + server.Start(new DummyApplication()); + + Assert.Equal(serverAddress, serverAddressesFeature.Addresses.Single()); + } + } + + [ConditionalFact] + public void DoesNotOverrideDirectConfigurationWithIServerAddressesFeature_IfAddressesIsEmpty() + { + var serverAddress = "http://localhost:11002/"; + + using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + { + var serverAddressesFeature = server.Features.Get(); + serverAddressesFeature.PreferHostingUrls = true; + server.Listener.Options.UrlPrefixes.Add(serverAddress); + + server.Start(new DummyApplication()); + + Assert.Equal(serverAddress, serverAddressesFeature.Addresses.Single()); + } + } + [ConditionalTheory] [InlineData("http://localhost:11001/")] [InlineData("invalid address")] From 4e8872b94d93afb5834ee4dfcbeb3dfd3b75c92d Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 28 Mar 2017 15:16:31 -0700 Subject: [PATCH 477/597] Implement IServer.StopAsync --- .../HttpSysOptions.cs | 6 ---- .../MessagePump.cs | 35 ++++++++++++------- .../MessagePumpTests.cs | 13 +++---- .../RequestTests.cs | 3 +- .../ServerTests.cs | 32 ++++++++++++++--- .../Utilities.cs | 5 +-- 6 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index 8b00e14e6a..85c8dcc2e1 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -79,12 +79,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - /// - /// The amount of time to wait for active requests to drain while the server is shutting down. - /// New requests will receive a 503 response in this time period. The default is 5 seconds. - /// - public TimeSpan ShutdownTimeout { get; set; } = TimeSpan.FromSeconds(5); - internal void SetRequestQueueLimit(RequestQueue requestQueue) { _requestQueue = requestQueue; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 01b8d831e8..e8aa2cca59 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private bool _stopping; private int _outstandingRequests; - private ManualResetEvent _shutdownSignal; + private TaskCompletionSource _shutdownSignal; private readonly ServerAddressesFeature _serverAddresses; @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _processRequest = new Action(ProcessRequestAsync); _maxAccepts = _options.MaxAccepts; EnableResponseCaching = _options.EnableResponseCaching; - _shutdownSignal = new ManualResetEvent(false); + _shutdownSignal = new TaskCompletionSource(); } internal HttpSysListener Listener { get; } @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public IFeatureCollection Features { get; } - public void Start(IHttpApplication application) + public Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) { if (application == null) { @@ -124,6 +124,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys Listener.Start(); ActivateRequestProcessingLimits(); + + return Task.CompletedTask; } private void ActivateRequestProcessingLimits() @@ -224,7 +226,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (Interlocked.Decrement(ref _outstandingRequests) == 0 && _stopping) { - _shutdownSignal.Set(); + LogHelper.LogInfo(_logger, "All requests drained."); + _shutdownSignal.TrySetResult(0); } } } @@ -242,24 +245,30 @@ namespace Microsoft.AspNetCore.Server.HttpSys context.Dispose(); } - public void Dispose() + public Task StopAsync(CancellationToken cancellationToken) { _stopping = true; // Wait for active requests to drain if (_outstandingRequests > 0) { LogHelper.LogInfo(_logger, "Stopping, waiting for " + _outstandingRequests + " request(s) to drain."); - var drained = _shutdownSignal.WaitOne(Listener.Options.ShutdownTimeout); - if (drained) - { - LogHelper.LogInfo(_logger, "All requests drained successfully."); - } - else + + var waitForStop = new TaskCompletionSource(); + cancellationToken.Register(() => { LogHelper.LogInfo(_logger, "Timed out, terminating " + _outstandingRequests + " request(s)."); - } + waitForStop.TrySetResult(0); + }); + + return Task.WhenAny(_shutdownSignal.Task, waitForStop.Task); } - // All requests are finished + + return Task.CompletedTask; + } + + public void Dispose() + { + _stopping = true; Listener.Dispose(); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs index 48913a746f..2bcd69e8c9 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; +using System.Threading; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; @@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys serverAddressesFeature.PreferHostingUrls = true; server.Listener.Options.UrlPrefixes.Add(serverAddress); - server.Start(new DummyApplication()); + server.StartAsync(new DummyApplication(), CancellationToken.None).Wait(); Assert.Equal(overrideAddress, serverAddressesFeature.Addresses.Single()); } @@ -46,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys serverAddressesFeature.Addresses.Add(overrideAddress); server.Listener.Options.UrlPrefixes.Add(serverAddress); - server.Start(new DummyApplication()); + server.StartAsync(new DummyApplication(), CancellationToken.None).Wait(); Assert.Equal(serverAddress, serverAddressesFeature.Addresses.Single()); } @@ -63,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys serverAddressesFeature.PreferHostingUrls = true; server.Listener.Options.UrlPrefixes.Add(serverAddress); - server.Start(new DummyApplication()); + server.StartAsync(new DummyApplication(), CancellationToken.None).Wait(); Assert.Equal(serverAddress, serverAddressesFeature.Addresses.Single()); } @@ -84,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys serverAddressesFeature.Addresses.Add(serverAddress); server.Listener.Options.UrlPrefixes.Add(overrideAddress); - server.Start(new DummyApplication()); + server.StartAsync(new DummyApplication(), CancellationToken.None).Wait(); Assert.Equal(overrideAddress, serverAddressesFeature.Addresses.Single()); } @@ -100,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var serverAddressesFeature = server.Features.Get(); serverAddressesFeature.Addresses.Add(serverAddress); - server.Start(new DummyApplication()); + server.StartAsync(new DummyApplication(), CancellationToken.None).Wait(); } } @@ -109,7 +110,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) { - server.Start(new DummyApplication()); + server.StartAsync(new DummyApplication(), CancellationToken.None).Wait(); Assert.Equal(Constants.DefaultServerAddress, server.Features.Get().Addresses.Single()); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs index 1e79dff31b..91e4459b78 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; @@ -312,7 +313,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path)); } - server.Start(new DummyApplication(app)); + server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait(); return server; } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 10a356b487..029c259b61 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Task responseTask; ManualResetEvent received = new ManualResetEvent(false); string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (var server = Utilities.CreateHttpServer(out address, httpContext => { received.Set(); httpContext.Response.ContentLength = 11; @@ -82,11 +82,34 @@ namespace Microsoft.AspNetCore.Server.HttpSys { responseTask = SendRequestAsync(address); Assert.True(received.WaitOne(10000)); + await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token); } string response = await responseTask; Assert.Equal("Hello World", response); } + [ConditionalFact] + public async Task Server_DisposeWithoutStopDuringRequest_Aborts() + { + Task responseTask; + var received = new ManualResetEvent(false); + var stopped = new ManualResetEvent(false); + string address; + using (var server = Utilities.CreateHttpServer(out address, httpContext => + { + received.Set(); + Assert.True(stopped.WaitOne(TimeSpan.FromSeconds(10))); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); + })) + { + responseTask = SendRequestAsync(address); + Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + } + stopped.Set(); + await Assert.ThrowsAsync(async () => await responseTask); + } + [ConditionalFact] public async Task Server_ShutdownDuringLongRunningRequest_TimesOut() { @@ -95,7 +118,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys bool? shutdown = null; var waitForShutdown = new ManualResetEvent(false); string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (var server = Utilities.CreateHttpServer(out address, httpContext => { received.Set(); shutdown = waitForShutdown.WaitOne(TimeSpan.FromSeconds(15)); @@ -105,8 +128,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys { responseTask = SendRequestAsync(address); Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + Assert.False(shutdown.HasValue); + await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token); } - Assert.False(shutdown.HasValue); waitForShutdown.Set(); await Assert.ThrowsAsync(async () => await responseTask); } @@ -271,7 +295,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys using (server) { - server.Start(new DummyApplication()); + await server.StartAsync(new DummyApplication(), CancellationToken.None); string response = await SendRequestAsync(address); Assert.Equal(string.Empty, response); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs index 3682e1de5e..5744e35d04 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Threading; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; @@ -55,7 +56,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys server.Listener.Options.Authentication.AllowAnonymous = allowAnonymous; try { - server.Start(new DummyApplication(app)); + server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait(); return server; } catch (HttpSysException) @@ -76,7 +77,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); server.Features.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); - server.Start(new DummyApplication(app)); + server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait(); return server; } } From 0ce85e2ea2ca24471f9208d66ab385b04c23d6d5 Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 18 Apr 2017 09:41:30 -0700 Subject: [PATCH 478/597] #263 Add Caching_SetTtlAndStatusCode_Cached test diagnostics --- .../Listener/ResponseCachingTests.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs index f731bbdd63..1505fd1dba 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs @@ -560,13 +560,28 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.CacheTtl = TimeSpan.FromSeconds(10); context.Dispose(); - var response = await responseTask; + HttpResponseMessage response; + try + { + response = await responseTask; + } + catch (Exception ex) + { + throw new Exception($"Failed to get first response for {status}", ex); + } Assert.Equal(status, (int)response.StatusCode); Assert.Equal(status.ToString(), response.Headers.GetValues("x-request-count").FirstOrDefault()); Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); // Send a second request and make sure we get the same response (without listening for one on the server). - response = await SendRequestAsync(address + status); + try + { + response = await SendRequestAsync(address + status); + } + catch (Exception ex) + { + throw new Exception($"Failed to get second response for {status}", ex); + } Assert.Equal(status, (int)response.StatusCode); Assert.Equal(status.ToString(), response.Headers.GetValues("x-request-count").FirstOrDefault()); Assert.Equal(new byte[0], await response.Content.ReadAsByteArrayAsync()); @@ -1137,7 +1152,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { using (var handler = new HttpClientHandler() { AllowAutoRedirect = false }) { - using (var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(5) }) + using (var client = new HttpClient(handler) { Timeout = Utilities.DefaultTimeout }) { var request = new HttpRequestMessage(new HttpMethod(method), uri); if (!string.IsNullOrEmpty(extraHeader)) From 76a4299b52579af86e3b64570b752fe9eeff72c4 Mon Sep 17 00:00:00 2001 From: Chris R Date: Wed, 19 Apr 2017 16:09:57 -0700 Subject: [PATCH 479/597] #326 Fix API set target --- .../NativeInterop/UnsafeNativeMethods.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs index c20f95f664..800bab4de2 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys #if NETSTANDARD1_3 private const string sspicli_LIB = "sspicli.dll"; private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; - private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-1.dll"; + private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-0.dll"; private const string api_ms_win_core_handle_LIB = "api-ms-win-core-handle-l1-1-0.dll"; private const string api_ms_win_core_libraryloader_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll"; private const string api_ms_win_core_heap_LIB = "api-ms-win-core-heap-L1-2-0.dll"; From 46beda328a3816abd2e1a9c02713d487828d21cb Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 24 Apr 2017 21:22:53 -0700 Subject: [PATCH 480/597] Skip flaky test --- .../Listener/ResponseBodyTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 072e2a25c4..46fcdda5e4 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -271,7 +271,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact] + [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] public async Task ResponseBodyWriteExceptions_FirstWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; From 142a13164e94e17d0e7319a3c46583e023602f69 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Apr 2017 11:04:08 -0700 Subject: [PATCH 481/597] Use Bundled NETStandard.Library \ NETCoreApp versions instead of explicitly specifying one --- build/common.props | 2 +- build/dependencies.props | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/build/common.props b/build/common.props index 5e264337e2..ba53fc2f1f 100644 --- a/build/common.props +++ b/build/common.props @@ -17,7 +17,7 @@ - + diff --git a/build/dependencies.props b/build/dependencies.props index 2867efab1d..461fc02ec9 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,10 +3,8 @@ 2.0.0-* 4.3.0 2.0.0-* - 1.6.1 - 2.0.0-* 4.3.1 15.0.0 2.2.0 - \ No newline at end of file + From a02d8b040566948c6283b33c053d4713845f8a11 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Apr 2017 22:02:51 -0700 Subject: [PATCH 482/597] Branching for 2.0.0-preview1 --- NuGet.config | 4 ++-- build.ps1 | 2 +- build.sh | 2 +- build/dependencies.props | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NuGet.config b/NuGet.config index 6f9f028ca1..2d69fec1ef 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + - + diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..225b1fe450 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..702b25c636 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi diff --git a/build/dependencies.props b/build/dependencies.props index 461fc02ec9..d1157e313f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.0.0-preview1-* 4.3.0 2.0.0-* 4.3.1 From 22f92e4aac8c459fbe8c92b15b6afba08577e4c6 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 26 Apr 2017 07:13:01 -0700 Subject: [PATCH 483/597] Updating package version to preview2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 10a1c898f3..019fba2829 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview1 + preview2 \ No newline at end of file From 169694053b1145ef7d0d9a1db2cb85ab7ddd25ab Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 1 May 2017 12:39:31 -0700 Subject: [PATCH 484/597] Use the bundled NETStandard.Library package in netstandard targeting libraries --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index d1157e313f..a016598653 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,6 +3,7 @@ 2.0.0-preview1-* 4.3.0 2.0.0-* + $(BundledNETStandardPackageVersion) 4.3.1 15.0.0 2.2.0 From fdfc8c01d1f102a8d92e09514cc129803044a863 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 5 May 2017 10:23:16 -0700 Subject: [PATCH 485/597] Update InternalAspNetCoreSdkVersion --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index a016598653..bd65b6ead4 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.0.0-preview1-* 4.3.0 - 2.0.0-* + 2.1.0-* $(BundledNETStandardPackageVersion) 4.3.1 15.0.0 From 31001de66a20d9e056247b558f421afedcf1d0b9 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Fri, 5 May 2017 12:42:01 -0700 Subject: [PATCH 486/597] Migrate to netcoreapp2.0 --- samples/HotAddSample/HotAddSample.csproj | 2 +- samples/HotAddSample/Startup.cs | 5 +-- samples/SelfHostServer/SelfHostServer.csproj | 2 +- samples/SelfHostServer/Startup.cs | 5 +-- .../HttpSysException.cs | 5 +-- ...Microsoft.AspNetCore.Server.HttpSys.csproj | 8 +--- .../NativeInterop/AddressFamily.cs | 9 ---- .../NativeInterop/ComNetOS.cs | 5 +-- .../NativeInterop/HttpSysSettings.cs | 9 ---- .../NativeInterop/NclUtilities.cs | 5 +-- .../NativeInterop/UnsafeNativeMethods.cs | 39 +--------------- .../RequestProcessing/OpaqueStream.cs | 8 ++-- .../RequestProcessing/RequestStream.cs | 16 ------- .../RequestProcessing/ResponseBody.cs | 11 +---- .../ResponseStream.cs | 12 +---- .../CriticalHandleZeroOrMinusOneIsInvalid.cs | 29 ------------ .../SafeHandleZeroOrMinusOneIsInvalid.cs | 28 ------------ .../AuthenticationTests.cs | 18 +++----- .../HttpsTests.cs | 12 ----- .../Listener/AuthenticationTests.cs | 15 +++---- .../Listener/HttpsTests.cs | 12 ----- .../Listener/RequestBodyTests.cs | 6 +-- .../Listener/ResponseBodyTests.cs | 44 ++----------------- .../Listener/ResponseHeaderTests.cs | 14 +----- .../Listener/ResponseSendFileTests.cs | 28 +----------- .../Listener/ServerTests.cs | 9 +--- .../Listener/SkipOffDomainAttribute.cs | 43 ------------------ .../Listener/Utilities.cs | 6 --- ...Core.Server.HttpSys.FunctionalTests.csproj | 3 +- .../RequestBodyTests.cs | 6 +-- .../ResponseBodyTests.cs | 13 +----- .../ResponseHeaderTests.cs | 12 ----- ...oft.AspNetCore.Server.HttpSys.Tests.csproj | 3 +- 33 files changed, 44 insertions(+), 398 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs delete mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index e9223fff1b..4a41f19c4c 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -3,7 +3,7 @@ - net46;netcoreapp2.0 + netcoreapp2.0 Exe true diff --git a/samples/HotAddSample/Startup.cs b/samples/HotAddSample/Startup.cs index f0ede45da9..58975d6aa6 100644 --- a/samples/HotAddSample/Startup.cs +++ b/samples/HotAddSample/Startup.cs @@ -23,10 +23,8 @@ namespace HotAddSample public HttpSysOptions ServerOptions { get; set; } - public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) + public void Configure(IApplicationBuilder app) { - loggerfactory.AddConsole(LogLevel.Information); - var addresses = ServerOptions.UrlPrefixes; addresses.Add("http://localhost:12346/pathBase/"); @@ -101,6 +99,7 @@ namespace HotAddSample public static void Main(string[] args) { var host = new WebHostBuilder() + .ConfigureLogging(factory => factory.AddConsole()) .UseStartup() .UseHttpSys() .Build(); diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index e9223fff1b..4a41f19c4c 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -3,7 +3,7 @@ - net46;netcoreapp2.0 + netcoreapp2.0 Exe true diff --git a/samples/SelfHostServer/Startup.cs b/samples/SelfHostServer/Startup.cs index f6c0381b23..52b65bd248 100644 --- a/samples/SelfHostServer/Startup.cs +++ b/samples/SelfHostServer/Startup.cs @@ -20,10 +20,8 @@ namespace SelfHostServer }); } - public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) + public void Configure(IApplicationBuilder app) { - loggerfactory.AddConsole(LogLevel.Debug); - app.Run(async context => { context.Response.ContentType = "text/plain"; @@ -34,6 +32,7 @@ namespace SelfHostServer public static void Main(string[] args) { var host = new WebHostBuilder() + .ConfigureLogging(factory => factory.AddConsole()) .UseStartup() .UseHttpSys(options => { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs index 7d9b6aa71e..9e65fa3916 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs @@ -25,13 +25,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys : base(errorCode, message) { } -#if NETSTANDARD1_3 - public int ErrorCode -#else + // the base class returns the HResult with this property // we need the Win32 Error Code, hence the override. public override int ErrorCode -#endif { get { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index 1f01f022d7..c001a825df 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -4,7 +4,7 @@ ASP.NET Core HTTP server that uses the Windows HTTP Server API. - net46;netstandard1.3 + netcoreapp2.0 $(NoWarn);CS1591 true true @@ -13,13 +13,9 @@ - - - - - + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs index 239d36533e..9f4a7063be 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs @@ -3,20 +3,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys { -#if NET46 - /// - /// - /// Specifies the address families that an instance of the - /// class can use. - /// - /// -#else /// /// /// Specifies the address families. /// /// -#endif internal enum AddressFamily { /// diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs index 8168e2c73d..12d1381bae 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs @@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { internal static class ComNetOS { + // Windows is assumed based on HttpApi.Supported which is checked in the HttpSysListener constructor. // Minimum support for Windows 7 is assumed. internal static readonly bool IsWin8orLater; @@ -15,11 +16,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var win8Version = new Version(6, 2); -#if NETSTANDARD1_3 - IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version); -#else IsWin8orLater = (Environment.OSVersion.Version >= win8Version); -#endif } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs index 704803bf88..d9efa35c8f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs @@ -6,17 +6,13 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Security; -#if !NETSTANDARD1_3 using Microsoft.Win32; -#endif namespace Microsoft.AspNetCore.Server.HttpSys { internal static class HttpSysSettings { -#if !NETSTANDARD1_3 private const string HttpSysParametersKey = @"System\CurrentControlSet\Services\HTTP\Parameters"; -#endif private const bool EnableNonUtf8Default = true; private const bool FavorUtf8Default = true; private const string EnableNonUtf8Name = "EnableNonUtf8"; @@ -41,10 +37,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } private static void ReadHttpSysRegistrySettings() -#if NETSTANDARD1_3 - { - } -#else { try { @@ -117,6 +109,5 @@ namespace Microsoft.AspNetCore.Server.HttpSys // TODO: log // Logging.PrintWarning(Logging.HttpListener, typeof(HttpSysSettings), methodName, SR.GetString(message, args)); } -#endif } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs index 3230b11dda..abd74045e5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs @@ -12,10 +12,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys get { return Environment.HasShutdownStarted -#if !NETSTANDARD1_3 - || AppDomain.CurrentDomain.IsFinalizingForUnload() -#endif - ; + || AppDomain.CurrentDomain.IsFinalizingForUnload(); } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs index 800bab4de2..81662ac8c1 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs @@ -9,7 +9,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys { internal static unsafe class UnsafeNclNativeMethods { -#if NETSTANDARD1_3 private const string sspicli_LIB = "sspicli.dll"; private const string api_ms_win_core_processthreads_LIB = "api-ms-win-core-processthreads-l1-1-1.dll"; private const string api_ms_win_core_io_LIB = "api-ms-win-core-io-l1-1-0.dll"; @@ -18,10 +17,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private const string api_ms_win_core_heap_LIB = "api-ms-win-core-heap-L1-2-0.dll"; private const string api_ms_win_core_heap_obsolete_LIB = "api-ms-win-core-heap-obsolete-L1-1-0.dll"; private const string api_ms_win_core_kernel32_legacy_LIB = "api-ms-win-core-kernel32-legacy-l1-1-0.dll"; -#else - private const string KERNEL32 = "kernel32.dll"; - private const string SECUR32 = "secur32.dll"; -#endif + private const string TOKENBINDING = "tokenbinding.dll"; // CONSIDER: Make this an enum, requires changing a lot of types from uint to ErrorCodes. @@ -39,18 +35,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal const uint ERROR_CONNECTION_INVALID = 1229; } -#if NETSTANDARD1_3 [DllImport(api_ms_win_core_io_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] -#endif internal static unsafe extern uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped); -#if NETSTANDARD1_3 [DllImport(api_ms_win_core_kernel32_legacy_LIB, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] -#endif internal static unsafe extern bool SetFileCompletionNotificationModes(SafeHandle handle, FileCompletionNotificationModes modes); [Flags] @@ -71,19 +59,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys [Out] out HeapAllocHandle resultList); // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366569(v=vs.85).aspx -#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)] -#else - [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)] -#endif internal static extern IntPtr GetProcessHeap(); // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366701(v=vs.85).aspx -#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)] -#else - [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)] -#endif internal static extern bool HeapFree( [In] IntPtr hHeap, [In] uint dwFlags, @@ -91,34 +71,17 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static class SafeNetHandles { -#if NETSTANDARD1_3 [DllImport(sspicli_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(SECUR32, ExactSpelling = true, SetLastError = true)] -#endif internal static extern int FreeContextBuffer( [In] IntPtr contextBuffer); -#if NETSTANDARD1_3 [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif internal static extern bool CloseHandle(IntPtr handle); -#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_obsolete_LIB, EntryPoint = "LocalAlloc", SetLastError = true)] -#else - [DllImport(KERNEL32, EntryPoint = "LocalAlloc", SetLastError = true)] -#endif - internal static extern SafeLocalFreeChannelBinding LocalAllocChannelBinding(int uFlags, UIntPtr sizetdwBytes); -#if NETSTANDARD1_3 [DllImport(api_ms_win_core_heap_obsolete_LIB, ExactSpelling = true, SetLastError = true)] -#else - [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] -#endif internal static extern IntPtr LocalFree(IntPtr handle); } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs index 40967efa7c..0bd9bba848 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { return _requestStream.ReadByte(); } -#if !NETSTANDARD1_3 + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _requestStream.BeginRead(buffer, offset, count, callback, state); @@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { return _requestStream.EndRead(asyncResult); } -#endif + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { return _requestStream.ReadAsync(buffer, offset, count, cancellationToken); @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { _responseStream.WriteByte(value); } -#if !NETSTANDARD1_3 + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _responseStream.BeginWrite(buffer, offset, count, callback, state); @@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { _responseStream.EndWrite(asyncResult); } -#endif + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { return _responseStream.WriteAsync(buffer, offset, count, cancellationToken); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index 94e7fa7553..0129c290e8 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -190,11 +190,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } -#if NETSTANDARD1_3 - public unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) -#else public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) -#endif { ValidateReadBuffer(buffer, offset, size); if (_closed) @@ -281,11 +277,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys return asyncResult; } -#if NETSTANDARD1_3 - public int EndRead(IAsyncResult asyncResult) -#else public override int EndRead(IAsyncResult asyncResult) -#endif { if (asyncResult == null) { @@ -416,20 +408,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if NETSTANDARD1_3 - public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) -#else public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) -#endif { throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } -#if NETSTANDARD1_3 - public void EndWrite(IAsyncResult asyncResult) -#else public override void EndWrite(IAsyncResult asyncResult) -#endif { throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs index e34f3184e5..506bba99a7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs @@ -374,7 +374,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } -#if !NETSTANDARD1_3 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); @@ -384,7 +383,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys { throw new InvalidOperationException(Resources.Exception_WriteOnlyStream); } -#endif #endregion @@ -477,19 +475,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } -#if NETSTANDARD1_3 - public IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) -#else public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) -#endif { return WriteAsync(buffer, offset, count).ToIAsyncResult(callback, state); } -#if NETSTANDARD1_3 - public void EndWrite(IAsyncResult asyncResult) -#else + public override void EndWrite(IAsyncResult asyncResult) -#endif { if (asyncResult == null) { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs index f326853545..130303482d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs @@ -39,7 +39,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count); -#if !NETSTANDARD1_3 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return _innerStream.BeginRead(buffer, offset, count, callback, state); @@ -49,7 +48,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys { return _innerStream.EndRead(asyncResult); } -#endif public override void Flush() { _onStart().GetAwaiter().GetResult(); @@ -73,19 +71,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys await _onStart(); await _innerStream.WriteAsync(buffer, offset, count, cancellationToken); } -#if NETSTANDARD1_3 - public IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) -#else + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) -#endif { return ToIAsyncResult(WriteAsync(buffer, offset, count), callback, state); } -#if NETSTANDARD1_3 - public void EndWrite(IAsyncResult asyncResult) -#else + public override void EndWrite(IAsyncResult asyncResult) -#endif { if (asyncResult == null) { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs deleted file mode 100644 index a7af472718..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/CriticalHandleZeroOrMinusOneIsInvalid.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if NETSTANDARD1_3 - -namespace Microsoft.Win32.SafeHandles -{ - using System; - using System.Runtime.InteropServices; - using System.Runtime.CompilerServices; - - // Class of critical handle which uses 0 or -1 as an invalid handle. - [System.Security.SecurityCritical] // auto-generated_required - internal abstract class CriticalHandleZeroOrMinusOneIsInvalid : CriticalHandle - { - protected CriticalHandleZeroOrMinusOneIsInvalid() - : base(IntPtr.Zero) - { - } - - public override bool IsInvalid - { - [System.Security.SecurityCritical] - get { return handle == new IntPtr(0) || handle == new IntPtr(-1); } - } - } -} - -#endif diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs deleted file mode 100644 index 3bf6498c75..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/fx/Microsoft/Win32/SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if NETSTANDARD1_3 - -namespace Microsoft.Win32.SafeHandles -{ - using System; - using System.Runtime.InteropServices; - using System.Runtime.CompilerServices; - - // Class of safe handle which uses 0 or -1 as an invalid handle. - [System.Security.SecurityCritical] // auto-generated_required - internal abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle - { - protected SafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) - : base(IntPtr.Zero, ownsHandle) - { - } - - public override bool IsInvalid - { - [System.Security.SecurityCritical] - get { return handle == new IntPtr(0) || handle == new IntPtr(-1); } - } - } -} -#endif diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index c5cddc6e6d..6c543f41e5 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -41,12 +41,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented [InlineData(AuthenticationSchemes.Basic)] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; @@ -61,12 +60,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented [InlineData(AuthenticationSchemes.Basic)] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; @@ -85,8 +83,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; @@ -285,13 +282,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { string address; @@ -310,13 +306,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { string address; @@ -338,12 +333,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationSchemes authType) { string address; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs index d42936325d..b3ae85687a 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs @@ -102,13 +102,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private async Task SendRequestAsync(string uri, X509Certificate cert = null) { -#if NET46 - var handler = new WebRequestHandler(); -#elif NETCOREAPP2_0 var handler = new WinHttpHandler(); -#else -#error Target framework needs to be updated -#endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; if (cert != null) { @@ -122,13 +116,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private async Task SendRequestAsync(string uri, string upload) { -#if NET46 - var handler = new WebRequestHandler(); -#elif NETCOREAPP2_0 var handler = new WinHttpHandler(); -#else -#error Target framework needs to be updated -#endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; using (HttpClient client = new HttpClient(handler)) { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs index 9281b71817..0ccc678909 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs @@ -41,12 +41,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalTheory] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented [InlineData(AuthenticationSchemes.Basic)] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { string address; @@ -61,12 +60,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalTheory] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented [InlineData(AuthenticationSchemes.Basic)] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { string address; @@ -87,8 +85,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/dotnet/corefx/issues/5045).")] + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; @@ -169,8 +166,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact] - [SkipOffDomain] + [ConditionalFact(Skip = "Requires a domain joined machine - https://github.com/aspnet/HttpSysServer/issues/357")] public async Task AuthTypes_RequireKerberosAuth_Success() { string address; @@ -189,8 +185,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact] - [SkipOffDomain] + [ConditionalFact(Skip = "Requires a domain joined machine - https://github.com/aspnet/HttpSysServer/issues/357")] public async Task MultipleAuthTypes_KerberosAllowAnonymousButSpecify401_ChallengesAdded() { string address; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs index 9075e8e831..4291f00e6e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs @@ -109,13 +109,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener private async Task SendRequestAsync(string uri, X509Certificate cert = null) { -#if NET46 - WebRequestHandler handler = new WebRequestHandler(); -#elif NETCOREAPP2_0 WinHttpHandler handler = new WinHttpHandler(); -#else -#error Target framework needs to be updated -#endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; if (cert != null) { @@ -129,13 +123,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener private async Task SendRequestAsync(string uri, string upload) { -#if NET46 - WebRequestHandler handler = new WebRequestHandler(); -#elif NETCOREAPP2_0 WinHttpHandler handler = new WinHttpHandler(); -#else -#error Target framework needs to be updated -#endif handler.ServerCertificateValidationCallback = (a, b, c, d) => true; using (HttpClient client = new HttpClient(handler)) { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index 78a37d1af7..d716e2a407 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Hello World", response); } } -#if NET46 + [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { @@ -72,10 +72,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Hello World", response); } } -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif [ConditionalFact] public async Task RequestBody_InvalidBuffer_ArgumentException() diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 46fcdda5e4..9fe7cea307 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -98,13 +98,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 30 "; var stream = context.Response.Body; -#if NET46 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); -#elif NETCOREAPP2_0 - await stream.WriteAsync(new byte[10], 0, 10); -#else -#error Target framework needs to be updated -#endif stream.Write(new byte[10], 0, 10); await stream.WriteAsync(new byte[10], 0, 10); context.Dispose(); @@ -131,15 +125,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#if NET46 - // HttpClient retries the request because it didn't get a response. - context = await server.AcceptAsync(Utilities.DefaultTimeout); - context.Response.Headers["Content-lenGth"] = " 20 "; - context.Dispose(); -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif + await Assert.ThrowsAsync(() => responseTask); } } @@ -287,19 +273,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET46 - // .NET 4.5 HttpClient automatically retries a request if it does not get a response. - context = await server.AcceptAsync(Utilities.DefaultTimeout); - cts = new CancellationTokenSource(); - cts.Cancel(); - // First write sends headers - writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); - Assert.True(writeTask.IsCanceled); - context.Dispose(); -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif + await Assert.ThrowsAsync(() => responseTask); } } @@ -319,19 +293,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET46 - // .NET 4.5 HttpClient automatically retries a request if it does not get a response. - context = await server.AcceptAsync(Utilities.DefaultTimeout); - cts = new CancellationTokenSource(); - cts.Cancel(); - // First write sends headers - writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); - Assert.True(writeTask.IsCanceled); - context.Dispose(); -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif + await Assert.ThrowsAsync(() => responseTask); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 1da87eab2c..f7aaa4c9cb 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -221,13 +221,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. + // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); -#elif NET46 - Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); -#else -#error Target framework needs to be updated -#endif } } @@ -252,13 +247,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. + // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); -#elif NET46 - Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); -#else -#error Target framework needs to be updated -#endif } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index b025dff302..e13c700717 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -362,19 +362,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET46 - // .NET 4.5 HttpClient automatically retries a request if it does not get a response. - context = await server.AcceptAsync(Utilities.DefaultTimeout); - cts = new CancellationTokenSource(); - cts.Cancel(); - // First write sends headers - writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); - Assert.True(writeTask.IsCanceled); - context.Dispose(); -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif + await Assert.ThrowsAsync(() => responseTask); } } @@ -394,19 +382,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#if NET46 - // .NET 4.5 HttpClient automatically retries a request if it does not get a response. - context = await server.AcceptAsync(Utilities.DefaultTimeout); - cts = new CancellationTokenSource(); - cts.Cancel(); - // First write sends headers - writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); - Assert.True(writeTask.IsCanceled); - context.Dispose(); -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif + await Assert.ThrowsAsync(() => responseTask); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index 6633fbbaca..5675d76a21 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -186,14 +186,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); -#if NET46 - // HttpClient re-tries the request because it doesn't know if the request was received. - context = await server.AcceptAsync(Utilities.DefaultTimeout); - context.Abort(); -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif + await Assert.ThrowsAsync(() => responseTask); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs deleted file mode 100644 index f74046ec1d..0000000000 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/SkipOffDomainAttribute.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.Testing.xunit; - -namespace Microsoft.AspNetCore.Server.HttpSys.Listener -{ - /// - /// Skips an auth test if the machine is not joined to a Windows domain. - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public class SkipOffDomainAttribute : Attribute, ITestCondition - { - public bool IsMet - { - get - { - try - { -#if NET46 - return !string.IsNullOrEmpty(System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name); -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif - } - catch - { - } - return false; - } - } - - public string SkipReason - { - get - { - return "Machine is not joined to a domain."; - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs index 8a5d5d9a55..db41469119 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs @@ -24,13 +24,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener static Utilities() { var win8Version = new Version(6, 2); -#if NET46 IsWin8orLater = (Environment.OSVersion.Version >= win8Version); -#elif NETCOREAPP2_0 - IsWin8orLater = (new Version(RuntimeEnvironment.OperatingSystemVersion) >= win8Version); -#else -#error Target framework needs to be updated -#endif } internal static HttpSysListener CreateHttpAuthServer(AuthenticationSchemes authScheme, bool allowAnonymos, out string baseAddress) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 809f73775c..1c0f20cb27 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -3,8 +3,7 @@ - netcoreapp2.0;net46 - netcoreapp2.0 + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs index b55b3f9d50..820c999da4 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Hello World", response); } } -#if NET46 + [ConditionalFact] public async Task RequestBody_ReadBeginEnd_Success() { @@ -68,10 +68,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Hello World", response); } } -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif [ConditionalFact] public async Task RequestBody_InvalidBuffer_ArgumentException() diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs index f35d322add..18dee99410 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs @@ -87,13 +87,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { httpContext.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = httpContext.Response.Body; -#if NET46 stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); -#elif NETCOREAPP2_0 - await stream.WriteAsync(new byte[10], 0, 10); -#else -#error Target framework needs to be updated -#endif stream.Write(new byte[10], 0, 10); await stream.WriteAsync(new byte[10], 0, 10); })) @@ -223,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); } } -#if NET46 + [ConditionalFact] public async Task ResponseBody_BeginWrite_TriggersOnStarting() { @@ -251,10 +245,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); } } -#elif NETCOREAPP2_0 -#else -#error Target framework needs to be updated -#endif + [ConditionalFact] public async Task ResponseBody_WriteAsync_TriggersOnStarting() { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index cc9f5ad87c..2153dde2ce 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -81,13 +81,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); -#elif NET46 - Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); -#else -#error Target framework needs to be updated -#endif } } @@ -111,13 +105,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); -#elif NET46 - Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); -#else -#error Target framework needs to be updated -#endif } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index cef136bb6b..dbf7edb1a7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -3,8 +3,7 @@ - netcoreapp2.0;net46 - netcoreapp2.0 + netcoreapp2.0 From 2eea53d82b888f0c12b52b18817647b14a6fa463 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 10 May 2017 11:31:47 -0700 Subject: [PATCH 487/597] Remove unnecessary package references (#359) --- build/dependencies.props | 1 - ...pNetCore.Server.HttpSys.FunctionalTests.csproj | 15 ++------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index de5a0cce37..09cfb1fe04 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,7 +4,6 @@ 4.3.0 2.1.0-* $(BundledNETStandardPackageVersion) - 4.3.1 15.0.0 2.2.0 diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 1c0f20cb27..198cec6ab5 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -1,4 +1,4 @@ - + @@ -13,20 +13,9 @@ + - - - - - - - - - - - - From 07ea0b08520f2bf4bf4c6488ca1b2706c409ffe2 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 15 May 2017 14:26:55 -0700 Subject: [PATCH 488/597] Upgrade test framework versions and fix test issues --- build/dependencies.props | 4 ++-- .../AuthenticationTests.cs | 2 +- .../Listener/AuthenticationTests.cs | 2 +- ...Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj | 4 ---- .../Microsoft.AspNetCore.Server.HttpSys.Tests.csproj | 4 ---- 5 files changed, 4 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 09cfb1fe04..ed2c89867f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,7 +4,7 @@ 4.3.0 2.1.0-* $(BundledNETStandardPackageVersion) - 15.0.0 - 2.2.0 + 15.3.0-* + 2.3.0-beta2-* diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index 6c543f41e5..678acc7934 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [Fact(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs index 0ccc678909..c189a04a32 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs @@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalFact(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 198cec6ab5..47ebda88eb 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -18,8 +18,4 @@ - - - - diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index dbf7edb1a7..36763d0a06 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -13,8 +13,4 @@ - - - - From bff13c7f43a92160f52318653d5c742ea65c2384 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Wed, 17 May 2017 13:35:09 -0700 Subject: [PATCH 489/597] HttpSysServer => Auth 2.0 --- .../AuthenticationHandler.cs | 141 ++++--------- .../FeatureContext.cs | 8 +- .../HttpSysDefaults.cs | 13 ++ .../MessagePump.cs | 10 +- ...Microsoft.AspNetCore.Server.HttpSys.csproj | 1 + .../WebHostBuilderHttpSysExtensions.cs | 1 + .../AuthenticationTests.cs | 191 +++++------------- .../MessagePumpTests.cs | 14 +- .../RequestTests.cs | 5 +- .../ServerTests.cs | 5 +- .../Utilities.cs | 52 ++++- 11 files changed, 174 insertions(+), 267 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs index 2daad5bb43..0f5e6702d2 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs @@ -4,9 +4,9 @@ using System; using System.Collections.Generic; using System.Security.Claims; -using System.Security.Principal; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Server.HttpSys @@ -14,138 +14,67 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal class AuthenticationHandler : IAuthenticationHandler { private RequestContext _requestContext; - private AuthenticationSchemes _authSchemes; - private AuthenticationSchemes _customChallenges; + private AuthenticationScheme _scheme; - internal AuthenticationHandler(RequestContext requestContext) - { - _requestContext = requestContext; - _authSchemes = requestContext.Response.AuthenticationChallenges; - _customChallenges = AuthenticationSchemes.None; - } - - public Task AuthenticateAsync(AuthenticateContext context) + public Task AuthenticateAsync() { var identity = _requestContext.User?.Identity; - - foreach (var authType in ListEnabledAuthSchemes()) + if (identity != null && identity.IsAuthenticated) { - var authScheme = authType.ToString(); - if (string.Equals(authScheme, context.AuthenticationScheme, StringComparison.Ordinal)) - { - if (identity != null && identity.IsAuthenticated - && string.Equals(authScheme, identity.AuthenticationType, StringComparison.Ordinal)) - { - context.Authenticated(_requestContext.User, properties: null, description: null); - } - else - { - context.NotAuthenticated(); - } - } + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(_requestContext.User, properties: null, authenticationScheme: _scheme.Name))); } - return TaskCache.CompletedTask; + return Task.FromResult(AuthenticateResult.None()); } public Task ChallengeAsync(ChallengeContext context) { - var automaticChallenge = string.Equals("Automatic", context.AuthenticationScheme, StringComparison.Ordinal); - foreach (var scheme in ListEnabledAuthSchemes()) + switch (context.Behavior) { - var authScheme = scheme.ToString(); - // Not including any auth types means it's a blanket challenge for any auth type. - if (automaticChallenge || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) - { - switch (context.Behavior) + case ChallengeBehavior.Forbidden: + _requestContext.Response.StatusCode = 403; + break; + case ChallengeBehavior.Unauthorized: + _requestContext.Response.StatusCode = 401; + break; + case ChallengeBehavior.Automatic: + var identity = (ClaimsIdentity)_requestContext.User?.Identity; + if (identity != null && identity.IsAuthenticated) { - case ChallengeBehavior.Forbidden: - _requestContext.Response.StatusCode = 403; - context.Accept(); - break; - case ChallengeBehavior.Unauthorized: - _requestContext.Response.StatusCode = 401; - _customChallenges |= scheme; - context.Accept(); - break; - case ChallengeBehavior.Automatic: - var identity = (ClaimsIdentity)_requestContext.User?.Identity; - if (identity != null && identity.IsAuthenticated - && (automaticChallenge || string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal))) - { - _requestContext.Response.StatusCode = 403; - context.Accept(); - } - else - { - _requestContext.Response.StatusCode = 401; - _customChallenges |= scheme; - context.Accept(); - } - break; - default: - throw new NotSupportedException(context.Behavior.ToString()); + _requestContext.Response.StatusCode = 403; } - } + else + { + _requestContext.Response.StatusCode = 401; + } + break; + default: + throw new NotSupportedException(context.Behavior.ToString()); } - // A challenge was issued, it overrides any pre-set auth types. - _requestContext.Response.AuthenticationChallenges = _customChallenges; + return TaskCache.CompletedTask; } - public void GetDescriptions(DescribeSchemesContext context) + public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) { - // TODO: Caching, this data doesn't change per request. - foreach (var scheme in ListEnabledAuthSchemes()) + _scheme = scheme; + _requestContext = context.Features.Get(); + + if (_requestContext == null) { - context.Accept(GetDescription(scheme.ToString())); + throw new InvalidOperationException("No RequestContext found."); } + + return TaskCache.CompletedTask; } public Task SignInAsync(SignInContext context) { - // Not supported. AuthenticationManager will throw if !Accepted. - return TaskCache.CompletedTask; + throw new NotSupportedException(); } public Task SignOutAsync(SignOutContext context) { - // Not supported. AuthenticationManager will throw if !Accepted. return TaskCache.CompletedTask; } - - private IDictionary GetDescription(string authenticationScheme) - { - return new Dictionary() - { - { "AuthenticationScheme", authenticationScheme }, - }; - } - - private IEnumerable ListEnabledAuthSchemes() - { - // Order by strength. - if ((_authSchemes & AuthenticationSchemes.Kerberos) == AuthenticationSchemes.Kerberos) - { - yield return AuthenticationSchemes.Kerberos; - } - if ((_authSchemes & AuthenticationSchemes.Negotiate) == AuthenticationSchemes.Negotiate) - { - yield return AuthenticationSchemes.Negotiate; - } - if ((_authSchemes & AuthenticationSchemes.NTLM) == AuthenticationSchemes.NTLM) - { - yield return AuthenticationSchemes.NTLM; - } - /*if ((_authSchemes & AuthenticationSchemes.Digest) == AuthenticationSchemes.Digest) - { - // TODO: - throw new NotImplementedException("Digest challenge generation has not been implemented."); - yield return AuthenticationSchemes.Digest; - }*/ - if ((_authSchemes & AuthenticationSchemes.Basic) == AuthenticationSchemes.Basic) - { - yield return AuthenticationSchemes.Basic; - } - } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index 9547a2ab3e..126d1212c7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -52,7 +52,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys private string _traceIdentitfier; private X509Certificate2 _clientCert; private ClaimsPrincipal _user; - private IAuthenticationHandler _authHandler; private CancellationToken _disconnectToken; private Stream _responseStream; private IHeaderDictionary _responseHeaders; @@ -68,7 +67,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys { _requestContext = requestContext; _features = new FeatureCollection(new StandardFeatureCollection(this)); - _authHandler = new AuthenticationHandler(requestContext); _enableResponseCaching = enableResponseCaching; // Pre-initialize any fields that are not lazy at the lower level. @@ -446,11 +444,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys set { _user = value; } } - IAuthenticationHandler IHttpAuthenticationFeature.Handler - { - get { return _authHandler; } - set { _authHandler = value; } - } + IAuthenticationHandler IHttpAuthenticationFeature.Handler { get; set; } string IHttpRequestIdentifierFeature.TraceIdentifier { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs new file mode 100644 index 0000000000..ea22e86d8e --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Server.HttpSys +{ + public static class HttpSysDefaults + { + /// + /// The name of the authentication scheme used. + /// + public static readonly string AuthenticationScheme = "Windows"; + } +} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index e8aa2cca59..54e2db7a5d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; @@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private readonly ServerAddressesFeature _serverAddresses; - public MessagePump(IOptions options, ILoggerFactory loggerFactory) + public MessagePump(IOptions options, ILoggerFactory loggerFactory, IAuthenticationSchemeProvider authentication) { if (options == null) { @@ -40,10 +41,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys { throw new ArgumentNullException(nameof(loggerFactory)); } - _options = options.Value; Listener = new HttpSysListener(_options, loggerFactory); _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); + + if (_options.Authentication.Schemes != AuthenticationSchemes.None) + { + authentication.AddScheme(new AuthenticationScheme(HttpSysDefaults.AuthenticationScheme, displayName: null, handlerType: typeof(AuthenticationHandler))); + } + Features = new FeatureCollection(); _serverAddresses = new ServerAddressesFeature(); Features.Set(_serverAddresses); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index c001a825df..d43ccbe0ca 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs index ff0d4b5ee9..d7042643b9 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs @@ -23,6 +23,7 @@ namespace Microsoft.AspNetCore.Hosting { return hostBuilder.ConfigureServices(services => { services.AddSingleton(); + services.AddAuthenticationCore(); }); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index 678acc7934..6c7618b5d3 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -26,8 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) { - string address; - using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -48,8 +47,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Basic)] public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) { - string address; - using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext => { throw new NotImplementedException(); })) @@ -67,8 +65,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Basic)] public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) { - string address; - using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -117,9 +114,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType) { - string address; int requestId = 0; - using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -153,8 +149,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) { - string address; - using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); @@ -167,61 +162,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] - [InlineData(AuthenticationSchemes.None)] - [InlineData(AuthenticationSchemes.Negotiate)] - [InlineData(AuthenticationSchemes.NTLM)] - // [InlineData(AuthenticationSchemes.Digest)] - [InlineData(AuthenticationSchemes.Basic)] - public async Task AuthTypes_GetSingleDescriptions(AuthenticationSchemes authType) - { - string address; - using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => - { - var resultList = httpContext.Authentication.GetAuthenticationSchemes(); - if (authType == AuthenticationSchemes.None) - { - Assert.Equal(0, resultList.Count()); - } - else - { - Assert.Equal(1, resultList.Count()); - var result = resultList.First(); - Assert.Equal(authType.ToString(), result.AuthenticationScheme); - Assert.Null(result.DisplayName); - } - - return Task.FromResult(0); - })) - { - var response = await SendRequestAsync(address); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(0, response.Headers.WwwAuthenticate.Count); - } - } - - [ConditionalFact] - public async Task AuthTypes_GetMultipleDescriptions() - { - string address; - AuthenticationSchemes authType = - AuthenticationSchemes.Negotiate - | AuthenticationSchemes.NTLM - | /*AuthenticationSchemes.Digest - |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => - { - var resultList = httpContext.Authentication.GetAuthenticationSchemes(); - Assert.Equal(3, resultList.Count()); - return Task.FromResult(0); - })) - { - var response = await SendRequestAsync(address); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(0, response.Headers.WwwAuthenticate.Count); - } - } - [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] @@ -230,18 +170,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationSchemes authType) { - string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, async httpContext => + using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, async httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.False(httpContext.User.Identity.IsAuthenticated); - foreach (var scheme in authTypeList) - { - var authResults = await httpContext.Authentication.AuthenticateAsync(scheme); - Assert.Null(authResults); - } + var authResults = await httpContext.AuthenticateAsync(HttpSysDefaults.AuthenticationScheme); + Assert.False(authResults.Succeeded); + Assert.True(authResults.Nothing); })) { var response = await SendRequestAsync(address); @@ -258,23 +195,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationSchemes authType) { - string address; - var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, async httpContext => + using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, async httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.True(httpContext.User.Identity.IsAuthenticated); - var count = 0; - foreach (var scheme in authTypeList) - { - var authResults = await httpContext.Authentication.AuthenticateAsync(scheme); - if (authResults != null) - { - count++; - } - } - Assert.Equal(1, count); + var authResults = await httpContext.AuthenticateAsync(HttpSysDefaults.AuthenticationScheme); + Assert.True(authResults.Succeeded); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); @@ -290,14 +217,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { - string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.False(httpContext.User.Identity.IsAuthenticated); - return httpContext.Authentication.ChallengeAsync(); + return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); })) { var response = await SendRequestAsync(address); @@ -314,17 +240,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationSchemes authType) { - string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, async httpContext => + using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, async httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.False(httpContext.User.Identity.IsAuthenticated); - foreach (var scheme in authTypeList) - { - await httpContext.Authentication.ChallengeAsync(scheme); - } + await httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); })) { var response = await SendRequestAsync(address); @@ -333,52 +255,47 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + [Fact(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + public async Task AuthTypes_OneChallengeSent() + { + var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; + using (var server = Utilities.CreateDynamicHost(authTypes, AllowAnoymous, out var address, httpContext => + { + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.False(httpContext.User.Identity.IsAuthenticated); + return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); + })) + { + var response = await SendRequestAsync(address); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(3, response.Headers.WwwAuthenticate.Count); + } + } + [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] [InlineData(AuthenticationSchemes.Basic)] - public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationSchemes authType) + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM)] + [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.Basic)] + [InlineData(AuthenticationSchemes.NTLM | AuthenticationSchemes.Basic)] + public async Task AuthTypes_ChallengeWillAskForAllEnabledSchemes(AuthenticationSchemes authType) { - string address; - var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext => + var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.False(httpContext.User.Identity.IsAuthenticated); - return httpContext.Authentication.ChallengeAsync(authType.ToString()); + return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); })) { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); - Assert.Equal(1, response.Headers.WwwAuthenticate.Count); - Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.First().Scheme); - } - } - - [ConditionalTheory] - [InlineData(AuthenticationSchemes.Negotiate)] - [InlineData(AuthenticationSchemes.NTLM)] - // [InlineData(AuthenticationSchemes.Digest)] - [InlineData(AuthenticationSchemes.Basic)] - public async Task AuthTypes_ChallengeDisabledAuthType_Error(AuthenticationSchemes authType) - { - string address; - var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - authTypes = authTypes & ~authType; - var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext => - { - Assert.NotNull(httpContext.User); - Assert.NotNull(httpContext.User.Identity); - Assert.False(httpContext.User.Identity.IsAuthenticated); - return Assert.ThrowsAsync(() => httpContext.Authentication.ChallengeAsync(authType.ToString())); - })) - { - var response = await SendRequestAsync(address); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count); } } @@ -389,14 +306,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys [InlineData(AuthenticationSchemes.Basic)] public async Task AuthTypes_Forbid_Forbidden(AuthenticationSchemes authType) { - string address; var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; - using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authTypes, AllowAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.False(httpContext.User.Identity.IsAuthenticated); - return httpContext.Authentication.ForbidAsync(authType.ToString()); + return httpContext.ForbidAsync(HttpSysDefaults.AuthenticationScheme); })) { var response = await SendRequestAsync(address); @@ -412,13 +328,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials public async Task AuthTypes_ChallengeAuthenticatedAuthType_Forbidden(AuthenticationSchemes authType) { - string address; - using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.True(httpContext.User.Identity.IsAuthenticated); - return httpContext.Authentication.ChallengeAsync(authType.ToString()); + return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); @@ -435,13 +350,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType) { - string address; - using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.True(httpContext.User.Identity.IsAuthenticated); - return httpContext.Authentication.ChallengeAsync(); + return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); @@ -458,13 +372,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials public async Task AuthTypes_UnathorizedAuthenticatedAuthType_Unauthorized(AuthenticationSchemes authType) { - string address; - using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext => + using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext => { Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.True(httpContext.User.Identity.IsAuthenticated); - return httpContext.Authentication.ChallengeAsync(authType.ToString(), null, ChallengeBehavior.Unauthorized); + return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme, null, ChallengeBehavior.Unauthorized); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs index 2bcd69e8c9..7232d97fe4 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; @@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var serverAddress = "http://localhost:11001/"; var overrideAddress = "http://localhost:11002/"; - using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + using (var server = Utilities.CreatePump()) { var serverAddressesFeature = server.Features.Get(); serverAddressesFeature.Addresses.Add(overrideAddress); @@ -41,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var serverAddress = "http://localhost:11002/"; - using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + using (var server = Utilities.CreatePump()) { var serverAddressesFeature = server.Features.Get(); serverAddressesFeature.Addresses.Add(overrideAddress); @@ -58,7 +59,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var serverAddress = "http://localhost:11002/"; - using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + using (var server = Utilities.CreatePump()) { var serverAddressesFeature = server.Features.Get(); serverAddressesFeature.PreferHostingUrls = true; @@ -79,7 +80,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var overrideAddress = "http://localhost:11002/"; - using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + using (var server = Utilities.CreatePump()) { var serverAddressesFeature = server.Features.Get(); serverAddressesFeature.Addresses.Add(serverAddress); @@ -96,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var serverAddress = "http://localhost:11001/"; - using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + using (var server = Utilities.CreatePump()) { var serverAddressesFeature = server.Features.Get(); serverAddressesFeature.Addresses.Add(serverAddress); @@ -108,12 +109,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys [ConditionalFact] public void UseDefaultAddress_WhenNoServerAddressAndNoDirectConfiguration() { - using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) + using (var server = Utilities.CreatePump()) { server.StartAsync(new DummyApplication(), CancellationToken.None).Wait(); Assert.Equal(Constants.DefaultServerAddress, server.Features.Get().Addresses.Single()); } } + } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs index 91e4459b78..56f8989859 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -9,6 +9,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; @@ -306,7 +307,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app); dynamicServer.Dispose(); var rootUri = new Uri(root); - var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); + var server = Utilities.CreatePump(); foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 029c259b61..28ec77a4fd 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -4,14 +4,13 @@ using System; using System.Collections.Generic; using System.IO; -using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -289,7 +288,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } - var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); + var server = Utilities.CreatePump(); server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address)); server.Listener.Options.RequestQueueLimit = 1001; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs index 5744e35d04..c1e2062890 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs @@ -3,9 +3,13 @@ using System; using System.Threading; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -38,6 +42,50 @@ namespace Microsoft.AspNetCore.Server.HttpSys return CreateDynamicHttpServer(string.Empty, authType, allowAnonymous, out root, out baseAddress, app); } + internal static IWebHost CreateDynamicHost(AuthenticationSchemes authType, bool allowAnonymous, out string root, RequestDelegate app) + => CreateDynamicHost(string.Empty, authType, allowAnonymous, out root, out var baseAddress, app); + + internal static IWebHost CreateDynamicHost(string basePath, AuthenticationSchemes authType, bool allowAnonymous, out string root, out string baseAddress, RequestDelegate app) + { + lock (PortLock) + { + while (NextPort < MaxPort) + { + var port = NextPort++; + var prefix = UrlPrefix.Create("http", "localhost", port, basePath); + root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; + baseAddress = prefix.ToString(); + + var builder = new WebHostBuilder() + .UseHttpSys(options => + { + options.UrlPrefixes.Add(prefix); + options.Authentication.Schemes = authType; + options.Authentication.AllowAnonymous = allowAnonymous; + }) + .Configure(appBuilder => appBuilder.Run(app)); + + var host = builder.Build(); + + + try + { + host.Start(); + return host; + } + catch (HttpSysException) + { + } + + } + NextPort = BasePort; + } + throw new Exception("Failed to locate a free port."); + } + + internal static MessagePump CreatePump() + => new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions()))); + internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, bool allowAnonymous, out string root, out string baseAddress, RequestDelegate app) { lock (PortLock) @@ -50,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; baseAddress = prefix.ToString(); - var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); + var server = CreatePump(); server.Features.Get().Addresses.Add(baseAddress); server.Listener.Options.Authentication.Schemes = authType; server.Listener.Options.Authentication.AllowAnonymous = allowAnonymous; @@ -75,7 +123,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static IServer CreateServer(string scheme, string host, int port, string path, RequestDelegate app) { - var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); + var server = CreatePump(); server.Features.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait(); return server; From df36d02311c05938a3ea57a31dc0a0790c63f564 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 22 May 2017 14:06:13 -0700 Subject: [PATCH 490/597] Retarget to netstandard2.0 --- build/common.props | 4 +- build/dependencies.props | 4 +- samples/HotAddSample/HotAddSample.csproj | 5 ++- samples/SelfHostServer/SelfHostServer.csproj | 5 ++- ...Microsoft.AspNetCore.Server.HttpSys.csproj | 2 +- .../AuthenticationTests.cs | 21 ++++++---- .../Listener/AuthenticationTests.cs | 9 +++-- .../Listener/ResponseBodyTests.cs | 38 +++++++++++++++++-- .../Listener/ResponseHeaderTests.cs | 14 ++++++- .../Listener/ResponseSendFileTests.cs | 28 +++++++++++++- .../Listener/ServerTests.cs | 9 ++++- ...Core.Server.HttpSys.FunctionalTests.csproj | 3 +- .../ResponseHeaderTests.cs | 12 ++++++ ...oft.AspNetCore.Server.HttpSys.Tests.csproj | 3 +- 14 files changed, 130 insertions(+), 27 deletions(-) diff --git a/build/common.props b/build/common.props index ba53fc2f1f..f336a03553 100644 --- a/build/common.props +++ b/build/common.props @@ -16,8 +16,8 @@ - - + + diff --git a/build/dependencies.props b/build/dependencies.props index ed2c89867f..75ab009a69 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,9 +1,9 @@ 2.0.0-* - 4.3.0 + 4.4.0-* 2.1.0-* - $(BundledNETStandardPackageVersion) + 2.0.0-* 15.3.0-* 2.3.0-beta2-* diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index 4a41f19c4c..a02b6162da 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -3,7 +3,7 @@ - netcoreapp2.0 + netcoreapp2.0;net461 Exe true @@ -13,4 +13,7 @@ + + + diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index 4a41f19c4c..a02b6162da 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -3,7 +3,7 @@ - netcoreapp2.0 + netcoreapp2.0;net461 Exe true @@ -13,4 +13,7 @@ + + + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index d43ccbe0ca..4bbc01835d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -4,7 +4,7 @@ ASP.NET Core HTTP server that uses the Windows HTTP Server API. - netcoreapp2.0 + netstandard2.0 $(NoWarn);CS1591 true true diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index 6c7618b5d3..59d5f49438 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -40,7 +40,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalTheory] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -58,7 +59,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalTheory] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -80,7 +82,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [Fact(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; @@ -209,7 +212,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalTheory] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -232,7 +236,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalTheory] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -255,7 +260,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [Fact(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task AuthTypes_OneChallengeSent() { var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; @@ -273,7 +279,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalTheory] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs index c189a04a32..13c75bbfd2 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs @@ -41,7 +41,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalTheory] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented @@ -60,7 +61,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalTheory] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -85,7 +87,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 9fe7cea307..c3e681b848 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -125,7 +125,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); - +#if NET461 + // HttpClient retries the request because it didn't get a response. + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Response.Headers["Content-lenGth"] = " 20 "; + context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated +#endif await Assert.ThrowsAsync(() => responseTask); } } @@ -273,7 +281,19 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); - +#if NET461 + // HttpClient retries the request because it didn't get a response. + context = await server.AcceptAsync(Utilities.DefaultTimeout); + cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated +#endif await Assert.ThrowsAsync(() => responseTask); } } @@ -293,7 +313,19 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); - +#if NET461 + // HttpClient retries the request because it didn't get a response. + context = await server.AcceptAsync(Utilities.DefaultTimeout); + cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated +#endif await Assert.ThrowsAsync(() => responseTask); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index f7aaa4c9cb..3ba6cba3b2 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -221,8 +221,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); - // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); +#elif NET461 + Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); +#else +#error Target framework needs to be updated +#endif } } @@ -247,8 +252,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); - // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); +#elif NET461 + Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); +#else +#error Target framework needs to be updated +#endif } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index e13c700717..f8d94e1087 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -362,7 +362,19 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); - +#if NET461 + // .NET HttpClient automatically retries a request if it does not get a response. + context = await server.AcceptAsync(Utilities.DefaultTimeout); + cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated +#endif await Assert.ThrowsAsync(() => responseTask); } } @@ -382,7 +394,19 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); - +#if NET461 + // .NET HttpClient automatically retries a request if it does not get a response. + context = await server.AcceptAsync(Utilities.DefaultTimeout); + cts = new CancellationTokenSource(); + cts.Cancel(); + // First write sends headers + writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); + Assert.True(writeTask.IsCanceled); + context.Dispose(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated +#endif await Assert.ThrowsAsync(() => responseTask); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index 5675d76a21..cbd7000614 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -186,7 +186,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Abort(); Assert.True(canceled.WaitOne(interval), "Aborted"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - +#if NET461 + // HttpClient re-tries the request because it doesn't know if the request was received. + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Abort(); +#elif NETCOREAPP2_0 +#else +#error Target framework needs to be updated +#endif await Assert.ThrowsAsync(() => responseTask); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 47ebda88eb..8db416c863 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + netcoreapp2.0;net461 + netcoreapp2.0 diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index 2153dde2ce..96b112ae59 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -81,7 +81,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); +#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); +#elif NET461 + Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); +#else +#error Target framework needs to be updated +#endif } } @@ -105,7 +111,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); +#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); +#elif NET461 + Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); +#else +#error Target framework needs to be updated +#endif } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index 36763d0a06..f8e1c7ff0f 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -3,7 +3,8 @@ - netcoreapp2.0 + netcoreapp2.0;net461 + netcoreapp2.0 From 9c5870b1b44986c6a85e04d0b4e85c6036e14ed0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 19 May 2017 07:53:50 -0700 Subject: [PATCH 491/597] React to StringSegment change --- src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index 126d1212c7..1b61b0fc6b 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -524,7 +524,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys // We require 'public' and 's-max-age' or 'max-age' or the Expires header. CacheControlHeaderValue cacheControl; - if (CacheControlHeaderValue.TryParse(cacheControlHeader, out cacheControl) && cacheControl.Public) + if (CacheControlHeaderValue.TryParse(cacheControlHeader.ToString(), out cacheControl) && cacheControl.Public) { if (cacheControl.SharedMaxAge.HasValue) { From bad3f62c8d6559a5ca7a609e53da8a14b6eeddcc Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 23 May 2017 14:52:22 -0700 Subject: [PATCH 492/597] React to StringSegment change. --- src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index 1b61b0fc6b..8d250e4ff1 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -536,7 +536,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } DateTimeOffset expirationDate; - if (HeaderUtilities.TryParseDate(response.Headers[HeaderNames.Expires], out expirationDate)) + if (HeaderUtilities.TryParseDate(response.Headers[HeaderNames.Expires].ToString(), out expirationDate)) { var expiresOffset = expirationDate - DateTimeOffset.UtcNow; if (expiresOffset > TimeSpan.Zero) From 87faa10e6478be2932ba41e8de09af8b5b9f9077 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Wed, 24 May 2017 12:21:08 -0700 Subject: [PATCH 493/597] React to forbid changes --- .../AuthenticationHandler.cs | 34 ++++---------- ...Microsoft.AspNetCore.Server.HttpSys.csproj | 1 + .../AuthenticationTests.cs | 46 +------------------ 3 files changed, 11 insertions(+), 70 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs index 0f5e6702d2..77656d1d96 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs @@ -26,31 +26,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys return Task.FromResult(AuthenticateResult.None()); } - public Task ChallengeAsync(ChallengeContext context) + public Task ChallengeAsync(AuthenticationProperties properties) { - switch (context.Behavior) - { - case ChallengeBehavior.Forbidden: - _requestContext.Response.StatusCode = 403; - break; - case ChallengeBehavior.Unauthorized: - _requestContext.Response.StatusCode = 401; - break; - case ChallengeBehavior.Automatic: - var identity = (ClaimsIdentity)_requestContext.User?.Identity; - if (identity != null && identity.IsAuthenticated) - { - _requestContext.Response.StatusCode = 403; - } - else - { - _requestContext.Response.StatusCode = 401; - } - break; - default: - throw new NotSupportedException(context.Behavior.ToString()); - } + _requestContext.Response.StatusCode = 401; + return TaskCache.CompletedTask; + } + public Task ForbidAsync(AuthenticationProperties properties) + { + _requestContext.Response.StatusCode = 403; return TaskCache.CompletedTask; } @@ -67,12 +51,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys return TaskCache.CompletedTask; } - public Task SignInAsync(SignInContext context) + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) { throw new NotSupportedException(); } - public Task SignOutAsync(SignOutContext context) + public Task SignOutAsync(AuthenticationProperties properties) { return TaskCache.CompletedTask; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index 4bbc01835d..139af2f47b 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -12,6 +12,7 @@ + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index 59d5f49438..bda1048f9c 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -328,50 +328,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] - [InlineData(AuthenticationSchemes.Negotiate)] - [InlineData(AuthenticationSchemes.NTLM)] - // [InlineData(AuthenticationSchemes.Digest)] // Not implemented - // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials - public async Task AuthTypes_ChallengeAuthenticatedAuthType_Forbidden(AuthenticationSchemes authType) - { - using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext => - { - Assert.NotNull(httpContext.User); - Assert.NotNull(httpContext.User.Identity); - Assert.True(httpContext.User.Identity.IsAuthenticated); - return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); - })) - { - var response = await SendRequestAsync(address, useDefaultCredentials: true); - Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); - // for some reason Kerberos and Negotiate include a 2nd stage challenge. - // Assert.Equal(0, response.Headers.WwwAuthenticate.Count); - } - } - - [ConditionalTheory] - [InlineData(AuthenticationSchemes.Negotiate)] - [InlineData(AuthenticationSchemes.NTLM)] - // [InlineData(AuthenticationSchemes.Digest)] // Not implemented - // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials - public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType) - { - using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext => - { - Assert.NotNull(httpContext.User); - Assert.NotNull(httpContext.User.Identity); - Assert.True(httpContext.User.Identity.IsAuthenticated); - return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); - })) - { - var response = await SendRequestAsync(address, useDefaultCredentials: true); - Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); - // for some reason Kerberos and Negotiate include a 2nd stage challenge. - // Assert.Equal(0, response.Headers.WwwAuthenticate.Count); - } - } - [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] @@ -384,7 +340,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User.Identity); Assert.True(httpContext.User.Identity.IsAuthenticated); - return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme, null, ChallengeBehavior.Unauthorized); + return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme, null); })) { var response = await SendRequestAsync(address, useDefaultCredentials: true); From d387e6b560a16604156fb6e9e824950f36bac8fe Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Thu, 25 May 2017 19:54:00 -0700 Subject: [PATCH 494/597] Fix package reference --- .../Microsoft.AspNetCore.Server.HttpSys.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index 139af2f47b..4bbc01835d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -12,7 +12,6 @@ - From a2c22afd7e334987be17ced77c05c187dad9a0e4 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Fri, 26 May 2017 12:40:59 -0700 Subject: [PATCH 495/597] Updated to use the latest shared runtime --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index 75ab009a69..bd5eaf78da 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,6 +4,7 @@ 4.4.0-* 2.1.0-* 2.0.0-* + 2.0.0-* 15.3.0-* 2.3.0-beta2-* From 32b30fe1546752417d6add74b79b4b02cb78bf7d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 31 May 2017 19:36:41 -0700 Subject: [PATCH 496/597] Branching for rel/2.0.0-preview2 --- NuGet.config | 3 ++- build/dependencies.props | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 6f9f028ca1..c4bc056c4d 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,8 @@  - + + diff --git a/build/dependencies.props b/build/dependencies.props index bd5eaf78da..37d0cd8854 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - 2.0.0-* + 2.0.0-preview2-* 4.4.0-* 2.1.0-* 2.0.0-* From e01d3db52fa1e1ae5dc83bdb7466f0aaea9bc0cf Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 31 May 2017 19:53:21 -0700 Subject: [PATCH 497/597] Updating build scripts to point to 2.0.0-preview2 KoreBuild --- build.ps1 | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..3a2476b2b4 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview2.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..a40bdb87b1 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0-preview2.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 7c19149d2a67afc0c42695f6c5962c9045e3f63e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 1 Jun 2017 10:47:06 -0700 Subject: [PATCH 498/597] Updating versions to preview3 --- NuGet.config | 3 ++- version.props | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index 6f9f028ca1..4e8a1f6de1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,8 +1,9 @@  + - \ No newline at end of file + diff --git a/version.props b/version.props index 019fba2829..a327eefab8 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview2 + preview3 \ No newline at end of file From f1901516c6682aea05cd0f2140fb3864a32bff62 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 5 Jun 2017 02:01:54 -0700 Subject: [PATCH 499/597] #519 Expose a connection limit option --- .../HttpSysListener.cs | 4 +- .../HttpSysOptions.cs | 37 +++++- .../NativeInterop/HttpApi.cs | 21 ++++ .../NativeInterop/UrlGroup.cs | 17 +++ .../ServerTests.cs | 106 ++++++++++++++++++ 5 files changed, 181 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs index c2bea54052..56d1e4356d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs @@ -146,9 +146,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys return; } - Options.Authentication.SetUrlGroupSecurity(UrlGroup); - Options.Timeouts.SetUrlGroupTimeouts(UrlGroup); - Options.SetRequestQueueLimit(RequestQueue); + Options.Apply(UrlGroup, RequestQueue); _requestQueue.AttachToUrlGroup(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index 85c8dcc2e1..7fc7089a15 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -12,7 +12,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys // The native request queue private long _requestQueueLength = DefaultRequestQueueLength; + private long? _maxConnections; private RequestQueue _requestQueue; + private UrlGroup _urlGroup; public HttpSysOptions() { @@ -54,6 +56,29 @@ namespace Microsoft.AspNetCore.Server.HttpSys /// public bool ThrowWriteExceptions { get; set; } + /// + /// Gets or sets the maximum number of concurrent connections to accept, -1 for infinite, or null to + /// use the machine wide setting from the registry. The default value is null. + /// + public long? MaxConnections + { + get => _maxConnections; + set + { + if (value.HasValue && value < -1) + { + throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty); + } + + if (value.HasValue && _urlGroup != null) + { + _urlGroup.SetMaxConnections(value.Value); + } + + _maxConnections = value; + } + } + /// /// Gets or sets the maximum number of requests that will be queued up in Http.Sys. /// @@ -79,13 +104,23 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - internal void SetRequestQueueLimit(RequestQueue requestQueue) + internal void Apply(UrlGroup urlGroup, RequestQueue requestQueue) { + _urlGroup = urlGroup; _requestQueue = requestQueue; + + if (_maxConnections.HasValue) + { + _urlGroup.SetMaxConnections(_maxConnections.Value); + } + if (_requestQueueLength != DefaultRequestQueueLength) { _requestQueue.SetLengthLimit(_requestQueueLength); } + + Authentication.SetUrlGroupSecurity(urlGroup); + Timeouts.SetUrlGroupTimeouts(urlGroup); } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs index fbea3b2fbc..94bc558af5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs @@ -544,6 +544,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys HttpRequestAuthTypeKerberos } + internal enum HTTP_QOS_SETTING_TYPE + { + HttpQosSettingTypeBandwidth, + HttpQosSettingTypeConnectionLimit, + HttpQosSettingTypeFlowRate + } + [StructLayout(LayoutKind.Sequential)] internal struct HTTP_SERVER_AUTHENTICATION_INFO { @@ -604,6 +611,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal IntPtr RequestQueueHandle; } + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_CONNECTION_LIMIT_INFO + { + internal HTTP_FLAGS Flags; + internal uint MaxConnections; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_QOS_SETTING_INFO + { + internal HTTP_QOS_SETTING_TYPE QosType; + internal IntPtr QosSetting; + } + // see http.w for definitions [Flags] internal enum HTTP_FLAGS : uint diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs index 2e69c0bcb4..cdeaae7800 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs @@ -3,12 +3,16 @@ using System; using System.Diagnostics; +using System.Runtime.InteropServices; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys { internal class UrlGroup : IDisposable { + private static readonly int QosInfoSize = + Marshal.SizeOf(); + private ServerSession _serverSession; private ILogger _logger; private bool _disposed; @@ -33,6 +37,19 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal ulong Id { get; private set; } + internal unsafe void SetMaxConnections(long maxConnections) + { + var connectionLimit = new HttpApi.HTTP_CONNECTION_LIMIT_INFO(); + connectionLimit.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + connectionLimit.MaxConnections = (uint)maxConnections; + + var qosSettings = new HttpApi.HTTP_QOS_SETTING_INFO(); + qosSettings.QosType = HttpApi.HTTP_QOS_SETTING_TYPE.HttpQosSettingTypeConnectionLimit; + qosSettings.QosSetting = new IntPtr(&connectionLimit); + + SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerQosProperty, new IntPtr(&qosSettings), (uint)QosInfoSize); + } + internal void SetProperty(HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) { Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 28ec77a4fd..4d8129d7f4 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -300,6 +300,112 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + [ConditionalFact] + public void Server_SetConnectionLimitArgumentValidation_Success() + { + var server = Utilities.CreatePump(); + + Assert.Null(server.Listener.Options.MaxConnections); + Assert.Throws(() => server.Listener.Options.MaxConnections = -2); + Assert.Null(server.Listener.Options.MaxConnections); + server.Listener.Options.MaxConnections = null; + server.Listener.Options.MaxConnections = 3; + } + + [ConditionalFact] + public async Task Server_SetConnectionLimit_Success() + { + // This is just to get a dynamic port + string address; + using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } + + var server = Utilities.CreatePump(); + server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address)); + Assert.Null(server.Listener.Options.MaxConnections); + server.Listener.Options.MaxConnections = 3; + + using (server) + { + await server.StartAsync(new DummyApplication(), CancellationToken.None); + + using (var client1 = await SendHungRequestAsync("GET", address)) + using (var client2 = await SendHungRequestAsync("GET", address)) + { + using (var client3 = await SendHungRequestAsync("GET", address)) + { + // Maxed out, refuses connection and throws + await Assert.ThrowsAsync(() => SendRequestAsync(address)); + } + + // A connection has been closed, try again. + string responseText = await SendRequestAsync(address); + Assert.Equal(string.Empty, responseText); + } + } + } + + [ConditionalFact] + public async Task Server_SetConnectionLimitChangeAfterStarted_Success() + { + // This is just to get a dynamic port + string address; + using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } + + var server = Utilities.CreatePump(); + server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address)); + Assert.Null(server.Listener.Options.MaxConnections); + server.Listener.Options.MaxConnections = 3; + + using (server) + { + await server.StartAsync(new DummyApplication(), CancellationToken.None); + + using (var client1 = await SendHungRequestAsync("GET", address)) + using (var client2 = await SendHungRequestAsync("GET", address)) + using (var client3 = await SendHungRequestAsync("GET", address)) + { + // Maxed out, refuses connection and throws + await Assert.ThrowsAsync(() => SendRequestAsync(address)); + + server.Listener.Options.MaxConnections = 4; + + string responseText = await SendRequestAsync(address); + Assert.Equal(string.Empty, responseText); + + server.Listener.Options.MaxConnections = 2; + + // Maxed out, refuses connection and throws + await Assert.ThrowsAsync(() => SendRequestAsync(address)); + } + } + } + + [ConditionalFact] + public async Task Server_SetConnectionLimitInfinite_Success() + { + // This is just to get a dynamic port + string address; + using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } + + var server = Utilities.CreatePump(); + server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address)); + server.Listener.Options.MaxConnections = -1; // infinite + + using (server) + { + await server.StartAsync(new DummyApplication(), CancellationToken.None); + + using (var client1 = await SendHungRequestAsync("GET", address)) + using (var client2 = await SendHungRequestAsync("GET", address)) + using (var client3 = await SendHungRequestAsync("GET", address)) + { + // Doesn't max out + string responseText = await SendRequestAsync(address); + Assert.Equal(string.Empty, responseText); + } + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) From 0e4405ab7f92f65be76d4051416e32db6b8e9c05 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 8 Jun 2017 11:44:04 -0700 Subject: [PATCH 500/597] Remove usage of TaskCache --- .../AuthenticationHandler.cs | 9 ++++----- .../FeatureContext.cs | 3 +-- .../Microsoft.AspNetCore.Server.HttpSys.csproj | 1 - .../DummyApplication.cs | 3 +-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs index 77656d1d96..9b3e4637b0 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs @@ -7,7 +7,6 @@ using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -29,13 +28,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys public Task ChallengeAsync(AuthenticationProperties properties) { _requestContext.Response.StatusCode = 401; - return TaskCache.CompletedTask; + return Task.CompletedTask; } public Task ForbidAsync(AuthenticationProperties properties) { _requestContext.Response.StatusCode = 403; - return TaskCache.CompletedTask; + return Task.CompletedTask; } public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) @@ -48,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys throw new InvalidOperationException("No RequestContext found."); } - return TaskCache.CompletedTask; + return Task.CompletedTask; } public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) @@ -58,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public Task SignOutAsync(AuthenticationProperties properties) { - return TaskCache.CompletedTask; + return Task.CompletedTask; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index 8d250e4ff1..f8eec7eeea 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -13,7 +13,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.Extensions.Internal; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Server.HttpSys @@ -553,7 +552,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (_completed) { - return TaskCache.CompletedTask; + return Task.CompletedTask; } _completed = true; return NotifyOnCompletedAsync(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index 4bbc01835d..2e8a9ab592 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -14,7 +14,6 @@ - diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs index 4d1f273e4a..14d975e1fa 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -14,7 +13,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { private readonly RequestDelegate _requestDelegate; - public DummyApplication() : this(context => TaskCache.CompletedTask) { } + public DummyApplication() : this(context => Task.CompletedTask) { } public DummyApplication(RequestDelegate requestDelegate) { From 216c2d159cb47d2e8722b20cb357b68c1244d362 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 26 Jun 2017 09:38:04 -0700 Subject: [PATCH 501/597] Adding libunwind8 to .travis.yml [skip appveyor] --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2a46104677..b10be14215 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,10 @@ os: - linux - osx osx_image: xcode8.2 +addons: + apt: + packages: + - libunwind8 branches: only: - master From c13ba3ef0a6a2cab06a592fe81602d406e1d368f Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 23 Jun 2017 17:55:55 -0700 Subject: [PATCH 502/597] #339 Don't send chunked responses for HEAD requests --- .../RequestProcessing/Response.cs | 4 +- .../Listener/ResponseHeaderTests.cs | 67 +++++++++++++------ 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index ec766cd8ae..427f1a1f2b 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -384,9 +384,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys // The application is performing it's own chunking. _boundaryType = BoundaryType.PassThrough; } - else if (endOfRequest && !(isHeadRequest && statusCanHaveBody)) // HEAD requests should always end without a body. Assume a GET response would have a body. + else if (endOfRequest) { - if (statusCanHaveBody) + if (!isHeadRequest && statusCanHaveBody) { Headers[HttpKnownHeaderNames.ContentLength] = Constants.Zero; } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 3ba6cba3b2..982024730e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -14,8 +14,15 @@ using Xunit; namespace Microsoft.AspNetCore.Server.HttpSys.Listener { - public class ResponseHeaderTests + public class ResponseHeaderTests : IDisposable { + private HttpClient _client = new HttpClient(); + + void IDisposable.Dispose() + { + _client.Dispose(); + } + [ConditionalFact] public async Task ResponseHeaders_11Request_ServerSendsDefaultHeaders() { @@ -74,12 +81,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener HttpResponseMessage response = await responseTask; response.EnsureSuccessStatusCode(); - Assert.Equal(3, response.Headers.Count()); - Assert.True(response.Headers.TransferEncodingChunked.Value); + Assert.Equal(2, response.Headers.Count()); + Assert.False(response.Headers.TransferEncodingChunked.HasValue); Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); Assert.Equal(0, response.Content.Headers.Count()); + + // Send a second request to check that the connection wasn't corrupted. + responseTask = SendHeadRequestAsync(address); + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + response = await responseTask; } } @@ -103,6 +116,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); Assert.Equal(0, response.Content.Headers.Count()); + + // Send a second request to check that the connection wasn't corrupted. + responseTask = SendHeadRequestAsync(address); + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + response = await responseTask; } } @@ -126,6 +145,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.Equal(1, response.Content.Headers.Count()); Assert.Equal(20, response.Content.Headers.ContentLength); + + // Send a second request to check that the connection wasn't corrupted. + responseTask = SendHeadRequestAsync(address); + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + response = await responseTask; } } @@ -172,6 +197,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); Assert.Equal(0, response.Content.Headers.Count()); + + // Send a second request to check that the connection wasn't corrupted. + responseTask = SendHeadRequestAsync(address); + context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + response = await responseTask; } } @@ -484,32 +515,26 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener private async Task SendRequestAsync(string uri, bool usehttp11 = true, bool sendKeepAlive = false) { - using (HttpClient client = new HttpClient()) + var request = new HttpRequestMessage(HttpMethod.Get, uri); + if (!usehttp11) { - var request = new HttpRequestMessage(HttpMethod.Get, uri); - if (!usehttp11) - { - request.Version = new Version(1, 0); - } - if (sendKeepAlive) - { - request.Headers.Add("Connection", "Keep-Alive"); - } - return await client.SendAsync(request); + request.Version = new Version(1, 0); } + if (sendKeepAlive) + { + request.Headers.Add("Connection", "Keep-Alive"); + } + return await _client.SendAsync(request); } private async Task SendHeadRequestAsync(string uri, bool usehttp11 = true) { - using (HttpClient client = new HttpClient()) + var request = new HttpRequestMessage(HttpMethod.Head, uri); + if (!usehttp11) { - var request = new HttpRequestMessage(HttpMethod.Head, uri); - if (!usehttp11) - { - request.Version = new Version(1, 0); - } - return await client.SendAsync(request); + request.Version = new Version(1, 0); } + return await _client.SendAsync(request); } } } \ No newline at end of file From 7b15720a05195c33cc17c2e8d0f31931acf43944 Mon Sep 17 00:00:00 2001 From: Chris R Date: Fri, 23 Jun 2017 14:11:51 -0700 Subject: [PATCH 503/597] # This is a combination of 2 commits. # This is the 1st commit message: #539 Implement request body size limit # The commit message #2 will be skipped: # Check exception messages --- .../FeatureContext.cs | 23 +- .../HttpSysOptions.cs | 27 ++ .../MessagePump.cs | 7 +- .../RequestProcessing/Request.cs | 32 +- .../RequestProcessing/RequestStream.cs | 131 ++++-- .../RequestStreamAsyncResult.cs | 8 +- .../StandardFeatureCollection.cs | 1 + .../RequestBodyLimitTests.cs | 422 ++++++++++++++++++ .../Utilities.cs | 34 +- 9 files changed, 609 insertions(+), 76 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index f8eec7eeea..b2e41d46aa 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -28,7 +28,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys IHttpRequestLifetimeFeature, IHttpAuthenticationFeature, IHttpUpgradeFeature, - IHttpRequestIdentifierFeature + IHttpRequestIdentifierFeature, + IHttpMaxRequestBodySizeFeature { private RequestContext _requestContext; private IFeatureCollection _features; @@ -62,11 +63,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys private bool _responseStarted; private bool _completed; - internal FeatureContext(RequestContext requestContext, bool enableResponseCaching) + internal FeatureContext(RequestContext requestContext) { _requestContext = requestContext; _features = new FeatureCollection(new StandardFeatureCollection(this)); - _enableResponseCaching = enableResponseCaching; + _enableResponseCaching = _requestContext.Server.Options.EnableResponseCaching; // Pre-initialize any fields that are not lazy at the lower level. _requestHeaders = Request.Headers; @@ -78,7 +79,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _scheme = Request.Scheme; _user = _requestContext.User; - _responseStream = new ResponseStream(requestContext.Response.Body, OnStart); + _responseStream = new ResponseStream(requestContext.Response.Body, OnResponseStart); _responseHeaders = Response.Headers; } @@ -405,7 +406,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys async Task IHttpSendFileFeature.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation) { - await OnStart(); + await OnResponseStart(); await Response.SendFileAsync(path, offset, length, cancellation); } @@ -433,7 +434,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys async Task IHttpUpgradeFeature.UpgradeAsync() { - await OnStart(); + await OnResponseStart(); return await _requestContext.UpgradeAsync(); } @@ -463,7 +464,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - internal async Task OnStart() + bool IHttpMaxRequestBodySizeFeature.IsReadOnly => Request.HasRequestBodyStarted; + + long? IHttpMaxRequestBodySizeFeature.MaxRequestBodySize + { + get => Request.MaxRequestBodySize; + set => Request.MaxRequestBodySize = value; + } + + internal async Task OnResponseStart() { if (_responseStarted) { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index 7fc7089a15..1d1e0cc00f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Http.Features; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -9,12 +10,16 @@ namespace Microsoft.AspNetCore.Server.HttpSys { private const long DefaultRequestQueueLength = 1000; // Http.sys default. internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; + // Matches the default maxAllowedContentLength in IIS (~28.6 MB) + // https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005 + private const long DefaultMaxRequestBodySize = 30000000; // The native request queue private long _requestQueueLength = DefaultRequestQueueLength; private long? _maxConnections; private RequestQueue _requestQueue; private UrlGroup _urlGroup; + private long? _maxRequestBodySize = DefaultMaxRequestBodySize; public HttpSysOptions() { @@ -104,6 +109,28 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + /// + /// Gets or sets the maximum allowed size of any request body in bytes. + /// When set to null, the maximum request body size is unlimited. + /// This limit has no effect on upgraded connections which are always unlimited. + /// This can be overridden per-request via . + /// + /// + /// Defaults to 30,000,000 bytes, which is approximately 28.6MB. + /// + public long? MaxRequestBodySize + { + get => _maxRequestBodySize; + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty); + } + _maxRequestBodySize = value; + } + } + internal void Apply(UrlGroup urlGroup, RequestQueue requestQueue) { _urlGroup = urlGroup; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 54e2db7a5d..82e6a03039 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -56,14 +56,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys _processRequest = new Action(ProcessRequestAsync); _maxAccepts = _options.MaxAccepts; - EnableResponseCaching = _options.EnableResponseCaching; _shutdownSignal = new TaskCompletionSource(); } internal HttpSysListener Listener { get; } - internal bool EnableResponseCaching { get; set; } - public IFeatureCollection Features { get; } public Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) @@ -199,12 +196,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys Interlocked.Increment(ref _outstandingRequests); try { - var featureContext = new FeatureContext(requestContext, EnableResponseCaching); + var featureContext = new FeatureContext(requestContext); context = _application.CreateContext(featureContext.Features); try { await _application.ProcessRequestAsync(context).SupressContext(); - await featureContext.OnStart(); + await featureContext.OnResponseStart(); requestContext.Dispose(); _application.DisposeContext(context, null); } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 043790f8e0..0147b84f03 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private BoundaryType _contentBoundaryType; private long? _contentLength; - private Stream _nativeStream; + private RequestStream _nativeStream; private SocketAddress _localEndPoint; private SocketAddress _remoteEndPoint; @@ -143,15 +143,32 @@ namespace Microsoft.AspNetCore.Server.HttpSys public string Method { get; } - public Stream Body + public Stream Body => EnsureRequestStream() ?? Stream.Null; + + private RequestStream EnsureRequestStream() { - get + if (_nativeStream == null && HasEntityBody) { - if (_nativeStream == null) + _nativeStream = new RequestStream(RequestContext) { - _nativeStream = HasEntityBody ? new RequestStream(RequestContext) : Stream.Null; + MaxSize = RequestContext.Server.Options.MaxRequestBodySize + }; + } + return _nativeStream; + } + + public bool HasRequestBodyStarted => _nativeStream?.HasStarted ?? false; + + public long? MaxRequestBodySize + { + get => EnsureRequestStream()?.MaxSize; + set + { + EnsureRequestStream(); + if (_nativeStream != null) + { + _nativeStream.MaxSize = value; } - return _nativeStream; } } @@ -319,10 +336,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal void SwitchToOpaqueMode() { - if (_nativeStream == null || _nativeStream == Stream.Null) + if (_nativeStream == null) { _nativeStream = new RequestStream(RequestContext); } + _nativeStream.SwitchToOpaqueMode(); } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index 0129c290e8..f8da3974c3 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Threading; @@ -17,6 +18,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys private RequestContext _requestContext; private uint _dataChunkOffset; private int _dataChunkIndex; + private long? _maxSize; + private long _totalRead; private bool _closed; internal RequestStream(RequestContext httpContext) @@ -35,68 +38,53 @@ namespace Microsoft.AspNetCore.Server.HttpSys private ILogger Logger => RequestContext.Server.Logger; - public override bool CanSeek + public bool HasStarted { get; private set; } + + public long? MaxSize { - get + get => _maxSize; + set { - return false; + if (HasStarted) + { + throw new InvalidOperationException("The maximum request size cannot be changed after the request body has started reading."); + } + if (value.HasValue && value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty); + } + _maxSize = value; } } - public override bool CanWrite - { - get - { - return false; - } - } + public override bool CanSeek => false; - public override bool CanRead - { - get - { - return true; - } - } + public override bool CanWrite => false; - public override long Length - { - get - { - throw new NotSupportedException(Resources.Exception_NoSeek); - } - } + public override bool CanRead => true; + + public override long Length => throw new NotSupportedException(Resources.Exception_NoSeek); public override long Position { - get - { - throw new NotSupportedException(Resources.Exception_NoSeek); - } - set - { - throw new NotSupportedException(Resources.Exception_NoSeek); - } + get => throw new NotSupportedException(Resources.Exception_NoSeek); + set => throw new NotSupportedException(Resources.Exception_NoSeek); } public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(Resources.Exception_NoSeek); - } + => throw new NotSupportedException(Resources.Exception_NoSeek); - public override void SetLength(long value) - { - throw new NotSupportedException(Resources.Exception_NoSeek); - } + public override void SetLength(long value) => throw new NotSupportedException(Resources.Exception_NoSeek); - public override void Flush() - { - throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); - } + public override void Flush() => throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); public override Task FlushAsync(CancellationToken cancellationToken) + => throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); + + internal void SwitchToOpaqueMode() { - throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); + HasStarted = true; + _maxSize = null; } internal void Abort() @@ -124,6 +112,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public override unsafe int Read([In, Out] byte[] buffer, int offset, int size) { ValidateReadBuffer(buffer, offset, size); + CheckSizeLimit(); if (_closed) { return 0; @@ -177,6 +166,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys } UpdateAfterRead(statusCode, dataRead); } + if (TryCheckSizeLimit((int)dataRead, out var ex)) + { + throw ex; + } // TODO: Verbose log dump data read return (int)dataRead; @@ -193,6 +186,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) { ValidateReadBuffer(buffer, offset, size); + CheckSizeLimit(); if (_closed) { RequestStreamAsyncResult result = new RequestStreamAsyncResult(this, state, callback); @@ -295,7 +289,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys castedAsyncResult.EndCalled = true; // wait & then check for errors // Throws on failure - int dataRead = castedAsyncResult.Task.Result; + int dataRead = castedAsyncResult.Task.GetAwaiter().GetResult(); // TODO: Verbose log #dataRead. return dataRead; } @@ -303,6 +297,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public override unsafe Task ReadAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken) { ValidateReadBuffer(buffer, offset, size); + CheckSizeLimit(); if (_closed) { return Task.FromResult(0); @@ -323,6 +318,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (_dataChunkIndex != -1 && dataRead == size) { UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead); + if (TryCheckSizeLimit((int)dataRead, out var exception)) + { + return Task.FromException(exception); + } // TODO: Verbose log #dataRead return Task.FromResult((int)dataRead); } @@ -378,6 +377,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys { uint totalRead = dataRead + bytesReturned; UpdateAfterRead(statusCode, totalRead); + if (TryCheckSizeLimit((int)totalRead, out var exception)) + { + return Task.FromException(exception); + } // TODO: Verbose log totalRead return Task.FromResult((int)totalRead); } @@ -396,6 +399,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys asyncResult.Dispose(); uint totalRead = dataRead + bytesReturned; UpdateAfterRead(statusCode, totalRead); + if (TryCheckSizeLimit((int)totalRead, out var exception)) + { + return Task.FromException(exception); + } // TODO: Verbose log return Task.FromResult((int)totalRead); } @@ -418,6 +425,40 @@ namespace Microsoft.AspNetCore.Server.HttpSys throw new InvalidOperationException(Resources.Exception_ReadOnlyStream); } + // Called before each read + private void CheckSizeLimit() + { + // Note SwitchToOpaqueMode sets HasStarted and clears _maxSize, so these limits don't apply. + if (!HasStarted) + { + var contentLength = RequestContext.Request.ContentLength; + if (contentLength.HasValue && _maxSize.HasValue && contentLength.Value > _maxSize.Value) + { + throw new IOException( + $"The request's Content-Length {contentLength.Value} is larger than the request body size limit {_maxSize.Value}."); + } + + HasStarted = true; + } + else if (TryCheckSizeLimit(0, out var exception)) + { + throw exception; + } + } + + // Called after each read. + internal bool TryCheckSizeLimit(int bytesRead, out Exception exception) + { + _totalRead += bytesRead; + if (_maxSize.HasValue && _totalRead > _maxSize.Value) + { + exception = new IOException($"The total number of bytes read {_totalRead} has exceeded the request body size limit {_maxSize.Value}."); + return true; + } + exception = null; + return false; + } + protected override void Dispose(bool disposing) { try diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs index 99f04d3fd9..5304f616f1 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs @@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } catch (Exception e) { - asyncResult.Fail(e); + asyncResult.Fail(new IOException(string.Empty, e)); } } @@ -112,7 +112,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal void Complete(int read, uint errorCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { - if (_tcs.TrySetResult(read + (int)DataAlreadyRead)) + if (_requestStream.TryCheckSizeLimit(read + (int)DataAlreadyRead, out var exception)) + { + _tcs.TrySetException(exception); + } + else if (_tcs.TrySetResult(read + (int)DataAlreadyRead)) { RequestStream.UpdateAfterRead((uint)errorCode, (uint)(read + DataAlreadyRead)); if (_callback != null) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs index 710286fc9d..d0fa5789dc 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs @@ -26,6 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { typeof(IHttpAuthenticationFeature), _identityFunc }, { typeof(IHttpRequestIdentifierFeature), _identityFunc }, { typeof(RequestContext), ctx => ctx.RequestContext }, + { typeof(IHttpMaxRequestBodySizeFeature), _identityFunc }, }; private readonly FeatureContext _featureContext; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs new file mode 100644 index 0000000000..039e81a1a4 --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs @@ -0,0 +1,422 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit; + +namespace Microsoft.AspNetCore.Server.HttpSys +{ + public class RequestBodyLimitTests + { + [ConditionalFact] + public async Task ContentLengthEqualsLimit_ReadSync_Success() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Equal(11, httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = httpContext.Request.Body.Read(input, 0, input.Length); + httpContext.Response.ContentLength = read; + httpContext.Response.Body.Write(input, 0, read); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World"); + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task ContentLengthEqualsLimit_ReadAync_Success() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Equal(11, httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); + httpContext.Response.ContentLength = read; + await httpContext.Response.Body.WriteAsync(input, 0, read); + })) + { + var response = await SendRequestAsync(address, "Hello World"); + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task ContentLengthEqualsLimit_ReadBeginEnd_Success() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Equal(11, httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = httpContext.Request.Body.EndRead(httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); + httpContext.Response.ContentLength = read; + httpContext.Response.Body.EndWrite(httpContext.Response.Body.BeginWrite(input, 0, read, null, null)); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World"); + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task ChunkedEqualsLimit_ReadSync_Success() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = httpContext.Request.Body.Read(input, 0, input.Length); + httpContext.Response.ContentLength = read; + httpContext.Response.Body.Write(input, 0, read); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World", chunked: true); + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task ChunkedEqualsLimit_ReadAync_Success() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); + httpContext.Response.ContentLength = read; + await httpContext.Response.Body.WriteAsync(input, 0, read); + })) + { + var response = await SendRequestAsync(address, "Hello World", chunked: true); + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task ChunkedEqualsLimit_ReadBeginEnd_Success() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = httpContext.Request.Body.EndRead(httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); + httpContext.Response.ContentLength = read; + httpContext.Response.Body.EndWrite(httpContext.Response.Body.BeginWrite(input, 0, read, null, null)); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World", chunked: true); + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task ContentLengthExceedsLimit_ReadSync_ThrowsImmidately() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Equal(11, httpContext.Request.ContentLength); + byte[] input = new byte[100]; + var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World"); + Assert.Equal(string.Empty, response); + } + } + + [ConditionalFact] + public async Task ContentLengthExceedsLimit_ReadAsync_ThrowsImmidately() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Equal(11, httpContext.Request.ContentLength); + byte[] input = new byte[100]; + var ex = Assert.Throws(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); }); + Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + ex = Assert.Throws(() => { var t = httpContext.Request.Body.ReadAsync(input, 0, input.Length); }); + Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World"); + Assert.Equal(string.Empty, response); + } + } + + [ConditionalFact] + public async Task ContentLengthExceedsLimit_ReadBeginEnd_ThrowsImmidately() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Equal(11, httpContext.Request.ContentLength); + byte[] input = new byte[100]; + var ex = Assert.Throws(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); + Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + ex = Assert.Throws(() => httpContext.Request.Body.BeginRead(input, 0, input.Length, null, null)); + Assert.Equal("The request's Content-Length 11 is larger than the request body size limit 10.", ex.Message); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World"); + Assert.Equal(string.Empty, response); + } + } + + [ConditionalFact] + public async Task ChunkedExceedsLimit_ReadSync_ThrowsAtLimit() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); + ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World", chunked: true); + Assert.Equal(string.Empty, response); + } + } + + [ConditionalFact] + public async Task ChunkedExceedsLimit_ReadAsync_ThrowsAtLimit() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, async httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + var ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); + Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); + ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); + Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); + })) + { + var response = await SendRequestAsync(address, "Hello World", chunked: true); + Assert.Equal(string.Empty, response); + } + } + + [ConditionalFact] + public async Task ChunkedExceedsLimit_ReadBeginEnd_ThrowsAtLimit() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + var body = httpContext.Request.Body; + var ex = Assert.Throws(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null))); + Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); + ex = Assert.Throws(() => body.EndRead(body.BeginRead(input, 0, input.Length, null, null))); + Assert.Equal("The total number of bytes read 11 has exceeded the request body size limit 10.", ex.Message); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, "Hello World", chunked: true); + Assert.Equal(string.Empty, response); + } + } + + [ConditionalFact] + public async Task Chunked_ReadSyncPartialBodyUnderLimit_ThrowsAfterLimit() + { + var content = new StaggardContent(); + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = httpContext.Request.Body.Read(input, 0, input.Length); + Assert.Equal(10, read); + content.Block.Release(); + var ex = Assert.Throws(() => httpContext.Request.Body.Read(input, 0, input.Length)); + Assert.Equal("The total number of bytes read 20 has exceeded the request body size limit 10.", ex.Message); + return Task.FromResult(0); + })) + { + string response = await SendRequestAsync(address, content, chunked: true); + Assert.Equal(string.Empty, response); + } + } + + [ConditionalFact] + public async Task Chunked_ReadAsyncPartialBodyUnderLimit_ThrowsAfterLimit() + { + var content = new StaggardContent(); + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, async httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); + Assert.Equal(10, read); + content.Block.Release(); + var ex = await Assert.ThrowsAsync(() => httpContext.Request.Body.ReadAsync(input, 0, input.Length)); + Assert.Equal("The total number of bytes read 20 has exceeded the request body size limit 10.", ex.Message); + })) + { + string response = await SendRequestAsync(address, content, chunked: true); + Assert.Equal(string.Empty, response); + } + } + + [ConditionalFact] + public async Task AdjustLimitPerRequest_ContentLength_ReadAync_Success() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Equal(11, feature.MaxRequestBodySize); + feature.MaxRequestBodySize = 12; + Assert.Equal(12, httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); + Assert.True(feature.IsReadOnly); + httpContext.Response.ContentLength = read; + await httpContext.Response.Body.WriteAsync(input, 0, read); + })) + { + var response = await SendRequestAsync(address, "Hello World!"); + Assert.Equal("Hello World!", response); + } + } + + [ConditionalFact] + public async Task AdjustLimitPerRequest_Chunked_ReadAync_Success() + { + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Equal(11, feature.MaxRequestBodySize); + feature.MaxRequestBodySize = 12; + Assert.Null(httpContext.Request.ContentLength); + byte[] input = new byte[100]; + int read = await httpContext.Request.Body.ReadAsync(input, 0, input.Length); + Assert.True(feature.IsReadOnly); + httpContext.Response.ContentLength = read; + await httpContext.Response.Body.WriteAsync(input, 0, read); + })) + { + var response = await SendRequestAsync(address, "Hello World!", chunked: true); + Assert.Equal("Hello World!", response); + } + } + + private Task SendRequestAsync(string uri, string upload, bool chunked = false) + { + return SendRequestAsync(uri, new StringContent(upload), chunked); + } + + private async Task SendRequestAsync(string uri, HttpContent content, bool chunked = false) + { + using (HttpClient client = new HttpClient()) + { + client.DefaultRequestHeaders.TransferEncodingChunked = chunked; + HttpResponseMessage response = await client.PostAsync(uri, content); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + } + + private class StaggardContent : HttpContent + { + public StaggardContent() + { + Block = new SemaphoreSlim(0, 1); + } + + public SemaphoreSlim Block { get; private set; } + + protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) + { + await stream.WriteAsync(new byte[10], 0, 10); + Assert.True(await Block.WaitAsync(TimeSpan.FromSeconds(10))); + await stream.WriteAsync(new byte[10], 0, 10); + } + + protected override bool TryComputeLength(out long length) + { + length = 10; + return true; + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs index c1e2062890..cecc4e270a 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs @@ -27,25 +27,41 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static IServer CreateHttpServer(out string baseAddress, RequestDelegate app) { string root; - return CreateDynamicHttpServer(string.Empty, AuthenticationSchemes.None, true, out root, out baseAddress, app); + return CreateDynamicHttpServer(string.Empty, out root, out baseAddress, options => { }, app); + } + + internal static IServer CreateHttpServer(out string baseAddress, Action configureOptions, RequestDelegate app) + { + string root; + return CreateDynamicHttpServer(string.Empty, out root, out baseAddress, configureOptions, app); } internal static IServer CreateHttpServerReturnRoot(string path, out string root, RequestDelegate app) { string baseAddress; - return CreateDynamicHttpServer(path, AuthenticationSchemes.None, true, out root, out baseAddress, app); + return CreateDynamicHttpServer(path, out root, out baseAddress, options => { }, app); } internal static IServer CreateHttpAuthServer(AuthenticationSchemes authType, bool allowAnonymous, out string baseAddress, RequestDelegate app) { string root; - return CreateDynamicHttpServer(string.Empty, authType, allowAnonymous, out root, out baseAddress, app); + return CreateDynamicHttpServer(string.Empty, out root, out baseAddress, options => + { + options.Authentication.Schemes = authType; + options.Authentication.AllowAnonymous = allowAnonymous; + }, app); } internal static IWebHost CreateDynamicHost(AuthenticationSchemes authType, bool allowAnonymous, out string root, RequestDelegate app) - => CreateDynamicHost(string.Empty, authType, allowAnonymous, out root, out var baseAddress, app); + { + return CreateDynamicHost(string.Empty, out root, out var baseAddress, options => + { + options.Authentication.Schemes = authType; + options.Authentication.AllowAnonymous = allowAnonymous; + }, app); + } - internal static IWebHost CreateDynamicHost(string basePath, AuthenticationSchemes authType, bool allowAnonymous, out string root, out string baseAddress, RequestDelegate app) + internal static IWebHost CreateDynamicHost(string basePath, out string root, out string baseAddress, Action configureOptions, RequestDelegate app) { lock (PortLock) { @@ -60,8 +76,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys .UseHttpSys(options => { options.UrlPrefixes.Add(prefix); - options.Authentication.Schemes = authType; - options.Authentication.AllowAnonymous = allowAnonymous; + configureOptions(options); }) .Configure(appBuilder => appBuilder.Run(app)); @@ -86,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static MessagePump CreatePump() => new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions()))); - internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, bool allowAnonymous, out string root, out string baseAddress, RequestDelegate app) + internal static IServer CreateDynamicHttpServer(string basePath, out string root, out string baseAddress, Action configureOptions, RequestDelegate app) { lock (PortLock) { @@ -100,8 +115,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var server = CreatePump(); server.Features.Get().Addresses.Add(baseAddress); - server.Listener.Options.Authentication.Schemes = authType; - server.Listener.Options.Authentication.AllowAnonymous = allowAnonymous; + configureOptions(server.Listener.Options); try { server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait(); From 7febdbaa2052125f764c939b873b415e7ba762e0 Mon Sep 17 00:00:00 2001 From: Chris R Date: Mon, 26 Jun 2017 15:17:35 -0700 Subject: [PATCH 504/597] #539 Implement request body size limit --- .../HttpSysOptions.cs | 6 +-- .../RequestProcessing/RequestStream.cs | 4 +- .../Listener/RequestBodyTests.cs | 2 +- .../OpaqueUpgradeTests.cs | 37 +++++++++++++++++++ .../RequestBodyLimitTests.cs | 14 +++---- .../RequestBodyTests.cs | 2 +- 6 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index 1d1e0cc00f..720eee3739 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (value.HasValue && value < -1) { - throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty); + throw new ArgumentOutOfRangeException(nameof(value), value, "The value must be positive, or -1 for infiniate."); } if (value.HasValue && _urlGroup != null) @@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (value <= 0) { - throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty); + throw new ArgumentOutOfRangeException(nameof(value), value, "The value must be greater than zero."); } if (_requestQueue != null) @@ -125,7 +125,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (value < 0) { - throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty); + throw new ArgumentOutOfRangeException(nameof(value), value, "The value must be greater or equal to zero."); } _maxRequestBodySize = value; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index f8da3974c3..ce7642dacf 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } if (value.HasValue && value < 0) { - throw new ArgumentOutOfRangeException(nameof(value), value, string.Empty); + throw new ArgumentOutOfRangeException(nameof(value), value, "The value must be greater or equal to zero."); } _maxSize = value; } @@ -289,7 +289,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys castedAsyncResult.EndCalled = true; // wait & then check for errors // Throws on failure - int dataRead = castedAsyncResult.Task.GetAwaiter().GetResult(); + var dataRead = castedAsyncResult.Task.GetAwaiter().GetResult(); // TODO: Verbose log #dataRead. return dataRead; } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index d716e2a407..b34cd35ed6 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } [ConditionalFact] - public async Task RequestBody_ReadAync_Success() + public async Task RequestBody_ReadAsync_Success() { string address; using (var server = Utilities.CreateHttpServer(out address)) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs index ef2c72e4c1..48421ddcaa 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs @@ -101,6 +101,43 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + [ConditionalFact] + [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] + public async Task OpaqueUpgrade_GetUpgrade_NotAffectedByMaxRequestBodyLimit() + { + ManualResetEvent waitHandle = new ManualResetEvent(false); + bool? upgraded = null; + string address; + using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, async httpContext => + { + var feature = httpContext.Features.Get(); + Assert.NotNull(feature); + Assert.False(feature.IsReadOnly); + Assert.Null(feature.MaxRequestBodySize); // GET/Upgrade requests don't actually have an entity body, so they can't set the limit. + + httpContext.Response.Headers["Upgrade"] = "websocket"; // Win8.1 blocks anything but WebSockets + var opaqueFeature = httpContext.Features.Get(); + Assert.NotNull(opaqueFeature); + Assert.True(opaqueFeature.IsUpgradableRequest); + var stream = await opaqueFeature.UpgradeAsync(); + Assert.True(feature.IsReadOnly); + Assert.Null(feature.MaxRequestBodySize); + Assert.Throws(() => feature.MaxRequestBodySize = 12); + Assert.Equal(15, stream.Read(new byte[15], 0, 15)); + upgraded = true; + waitHandle.Set(); + })) + { + using (Stream stream = await SendOpaqueRequestAsync("GET", address)) + { + stream.Write(new byte[15], 0, 15); + Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); + Assert.True(upgraded.HasValue, "Upgraded not set"); + Assert.True(upgraded.Value, "Upgrade failed"); + } + } + } + [ConditionalFact] [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_WithOnStarting_CallbackCalled() diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs index 039e81a1a4..ed835f345f 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task ContentLengthEqualsLimit_ReadAync_Success() + public async Task ContentLengthEqualsLimit_ReadAsync_Success() { string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext => @@ -103,7 +103,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task ChunkedEqualsLimit_ReadAync_Success() + public async Task ChunkedEqualsLimit_ReadAsync_Success() { string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext => @@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task ContentLengthExceedsLimit_ReadSync_ThrowsImmidately() + public async Task ContentLengthExceedsLimit_ReadSync_ThrowsImmediately() { string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => @@ -169,7 +169,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task ContentLengthExceedsLimit_ReadAsync_ThrowsImmidately() + public async Task ContentLengthExceedsLimit_ReadAsync_ThrowsImmediately() { string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => @@ -192,7 +192,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task ContentLengthExceedsLimit_ReadBeginEnd_ThrowsImmidately() + public async Task ContentLengthExceedsLimit_ReadBeginEnd_ThrowsImmediately() { string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => @@ -333,7 +333,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task AdjustLimitPerRequest_ContentLength_ReadAync_Success() + public async Task AdjustLimitPerRequest_ContentLength_ReadAsync_Success() { string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext => @@ -357,7 +357,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task AdjustLimitPerRequest_Chunked_ReadAync_Success() + public async Task AdjustLimitPerRequest_Chunked_ReadAsync_Success() { string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, async httpContext => diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs index 820c999da4..23c7c56be1 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public async Task RequestBody_ReadAync_Success() + public async Task RequestBody_ReadAsync_Success() { string address; using (Utilities.CreateHttpServer(out address, async httpContext => From 432c4c32b283e9781bb884605475a8072a6a06c1 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 29 Jun 2017 08:02:19 -0700 Subject: [PATCH 505/597] Add NETStandardImplicitPackageVersion --- build/dependencies.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index bd5eaf78da..5265f399a5 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,8 +1,9 @@ - + 2.0.0-* 4.4.0-* 2.1.0-* + 2.0.0-* 2.0.0-* 2.0.0-* 15.3.0-* From 779cfd265a5d82bcaa00268c1245b9f70ad74bd7 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Tue, 27 Jun 2017 14:59:21 -0700 Subject: [PATCH 506/597] React to HttpAbstractions --- .../AuthenticationHandler.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs index 9b3e4637b0..f8edd9ccd7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(_requestContext.User, properties: null, authenticationScheme: _scheme.Name))); } - return Task.FromResult(AuthenticateResult.None()); + return Task.FromResult(AuthenticateResult.NoResult()); } public Task ChallengeAsync(AuthenticationProperties properties) @@ -49,15 +49,5 @@ namespace Microsoft.AspNetCore.Server.HttpSys return Task.CompletedTask; } - - public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) - { - throw new NotSupportedException(); - } - - public Task SignOutAsync(AuthenticationProperties properties) - { - return Task.CompletedTask; - } } } \ No newline at end of file From 2e2cbccbdd53efdbfbdc6ad8dfec2fb5496a998f Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Wed, 28 Jun 2017 12:59:24 -0700 Subject: [PATCH 507/597] Fix tests --- .../AuthenticationTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index bda1048f9c..ebb092b746 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -181,7 +181,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(httpContext.User.Identity.IsAuthenticated); var authResults = await httpContext.AuthenticateAsync(HttpSysDefaults.AuthenticationScheme); Assert.False(authResults.Succeeded); - Assert.True(authResults.Nothing); + Assert.True(authResults.None); })) { var response = await SendRequestAsync(address); From ac4157c6276e72887e0a11dd648952d5faa9d72f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 3 Jul 2017 14:06:09 -0700 Subject: [PATCH 508/597] Update LICENSE.txt text --- LICENSE.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 0bdc1962b6..7b2956ecee 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,10 +1,12 @@ -Copyright (c) .NET Foundation. All rights reserved. +Copyright (c) .NET Foundation and Contributors + +All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use -these files except in compliance with the License. You may obtain a copy of the +this file except in compliance with the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR From 13b867a90eefb17094d7d02c935d82408e58f5ee Mon Sep 17 00:00:00 2001 From: Chris R Date: Tue, 27 Jun 2017 11:48:48 -0700 Subject: [PATCH 509/597] #366 Add flag to disable synchronous IO --- .../FeatureContext.cs | 9 +++- .../HttpSysOptions.cs | 6 +++ .../RequestProcessing/Request.cs | 6 +-- .../RequestProcessing/RequestContext.cs | 3 ++ .../RequestProcessing/RequestStream.cs | 6 +++ .../RequestProcessing/ResponseBody.cs | 12 ++++++ .../StandardFeatureCollection.cs | 1 + .../Listener/HttpsTests.cs | 7 ++- .../Listener/OpaqueUpgradeTests.cs | 2 +- .../Listener/RequestBodyTests.cs | 29 +++++++++++++ .../Listener/ResponseBodyTests.cs | 43 +++++++++++++++++++ .../Listener/ResponseCachingTests.cs | 17 ++++---- .../Listener/ResponseHeaderTests.cs | 1 + .../Listener/ServerTests.cs | 23 +++++----- .../OpaqueUpgradeTests.cs | 4 +- .../RequestBodyLimitTests.cs | 5 +++ .../RequestBodyTests.cs | 4 ++ .../ResponseBodyTests.cs | 17 +++++--- .../ResponseHeaderTests.cs | 4 +- .../ServerTests.cs | 6 +-- 20 files changed, 161 insertions(+), 44 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs index b2e41d46aa..9acef96deb 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs @@ -29,7 +29,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys IHttpAuthenticationFeature, IHttpUpgradeFeature, IHttpRequestIdentifierFeature, - IHttpMaxRequestBodySizeFeature + IHttpMaxRequestBodySizeFeature, + IHttpBodyControlFeature { private RequestContext _requestContext; private IFeatureCollection _features; @@ -464,6 +465,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + bool IHttpBodyControlFeature.AllowSynchronousIO + { + get => _requestContext.AllowSynchronousIO; + set => _requestContext.AllowSynchronousIO = value; + } + bool IHttpMaxRequestBodySizeFeature.IsReadOnly => Request.HasRequestBodyStarted; long? IHttpMaxRequestBodySizeFeature.MaxRequestBodySize diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index 720eee3739..cf34e6e368 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -131,6 +131,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + /// + /// Gets or sets a value that controls whether synchronous IO is allowed for the HttpContext.Request.Body and HttpContext.Response.Body. + /// The default is `true`. + /// + public bool AllowSynchronousIO { get; set; } = true; + internal void Apply(UrlGroup urlGroup, RequestQueue requestQueue) { _urlGroup = urlGroup; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 0147b84f03..7e4ef322d6 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -23,6 +23,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys // private byte[] _referredTokenBindingId; private BoundaryType _contentBoundaryType; + private long? _contentLength; private RequestStream _nativeStream; @@ -149,10 +150,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (_nativeStream == null && HasEntityBody) { - _nativeStream = new RequestStream(RequestContext) - { - MaxSize = RequestContext.Server.Options.MaxRequestBodySize - }; + _nativeStream = new RequestStream(RequestContext); } return _nativeStream; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index 22b3ca6b13..a57064fb55 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -30,6 +30,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys _memoryBlob = memoryBlob; Request = new Request(this, _memoryBlob); Response = new Response(this); + AllowSynchronousIO = server.Options.AllowSynchronousIO; } internal HttpSysListener Server { get; } @@ -88,6 +89,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys public bool IsUpgradableRequest => Request.IsUpgradable; + internal bool AllowSynchronousIO { get; set; } + public Task UpgradeAsync() { if (!IsUpgradableRequest) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index ce7642dacf..baef4c5a9f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -25,6 +25,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal RequestStream(RequestContext httpContext) { _requestContext = httpContext; + _maxSize = _requestContext.Server.Options.MaxRequestBodySize; } internal RequestContext RequestContext @@ -111,6 +112,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys public override unsafe int Read([In, Out] byte[] buffer, int offset, int size) { + if (!RequestContext.AllowSynchronousIO) + { + throw new InvalidOperationException("Synchronous IO APIs are disabled, see AllowSynchronousIO."); + } + ValidateReadBuffer(buffer, offset, size); CheckSizeLimit(); if (_closed) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs index 506bba99a7..35eb89c6e7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs @@ -91,10 +91,16 @@ namespace Microsoft.AspNetCore.Server.HttpSys // Send headers public override void Flush() { + if (!RequestContext.AllowSynchronousIO) + { + throw new InvalidOperationException("Synchronous IO APIs are disabled, see AllowSynchronousIO."); + } + if (_disposed) { return; } + FlushInternal(endOfRequest: false); } @@ -449,9 +455,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys public override void Write(byte[] buffer, int offset, int count) { + if (!RequestContext.AllowSynchronousIO) + { + throw new InvalidOperationException("Synchronous IO APIs are disabled, see AllowSynchronousIO."); + } + // Validates for null and bounds. Allows count == 0. // TODO: Verbose log parameters var data = new ArraySegment(buffer, offset, count); + CheckDisposed(); CheckWriteCount(count); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs index d0fa5789dc..0830de0fec 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs @@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { typeof(IHttpRequestIdentifierFeature), _identityFunc }, { typeof(RequestContext), ctx => ctx.RequestContext }, { typeof(IHttpMaxRequestBodySizeFeature), _identityFunc }, + { typeof(IHttpBodyControlFeature), _identityFunc }, }; private readonly FeatureContext _featureContext; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs index 4291f00e6e..a4c16c785c 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs @@ -60,10 +60,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string input = new StreamReader(context.Request.Body).ReadToEnd(); Assert.Equal("Hello World", input); context.Response.ContentLength = 11; - using (var writer = new StreamWriter(context.Response.Body)) - { - writer.Write("Hello World"); - } + var writer = new StreamWriter(context.Response.Body); + await writer.WriteAsync("Hello World"); + await writer.FlushAsync(); string response = await responseTask; Assert.Equal("Hello World", response); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs index 26cc299f09..d749fdb285 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] body = Encoding.UTF8.GetBytes("Hello World"); - context.Response.Body.Write(body, 0, body.Length); + await context.Response.Body.WriteAsync(body, 0, body.Length); Assert.Throws(() => context.Response.Headers["Upgrade"] = "WebSocket"); // Win8.1 blocks anything but WebSocket await Assert.ThrowsAsync(async () => await context.UpgradeAsync()); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index b34cd35ed6..9ea7f4805f 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -16,6 +16,32 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class RequestBodyTests { + [ConditionalFact] + public async Task RequestBody_SyncReadEnabledByDefault_ThrowsWhenDisabled() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + Task responseTask = SendRequestAsync(address, "Hello World"); + + Assert.True(server.Options.AllowSynchronousIO); + + var context = await server.AcceptAsync(Utilities.DefaultTimeout); + byte[] input = new byte[100]; + + Assert.True(context.AllowSynchronousIO); + var read = context.Request.Body.Read(input, 0, input.Length); + context.Response.ContentLength = read; + context.Response.Body.Write(input, 0, read); + + context.AllowSynchronousIO = false; + Assert.Throws(() => context.Request.Body.Read(input, 0, input.Length)); + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + [ConditionalFact] public async Task RequestBody_ReadSync_Success() { @@ -24,6 +50,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { Task responseTask = SendRequestAsync(address, "Hello World"); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[100]; int read = context.Request.Body.Read(input, 0, input.Length); @@ -81,6 +108,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { Task responseTask = SendRequestAsync(address, "Hello World"); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[100]; Assert.Throws("buffer", () => context.Request.Body.Read(null, 0, 1)); @@ -106,6 +134,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { Task responseTask = SendRequestAsync(address, content); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); byte[] input = new byte[10]; int read = context.Request.Body.Read(input, 0, input.Length); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index c3e681b848..c41ef371a7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -16,6 +16,41 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { public class ResponseBodyTests { + [ConditionalFact] + public async Task ResponseBody_SyncWriteEnabledByDefault_ThrowsWhenDisabled() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(Utilities.DefaultTimeout); + + Assert.True(context.AllowSynchronousIO); + + context.Response.Body.Flush(); + context.Response.Body.Write(new byte[10], 0, 10); + context.Response.Body.Flush(); + + context.AllowSynchronousIO = false; + + Assert.Throws(() => context.Response.Body.Flush()); + Assert.Throws(() => context.Response.Body.Write(new byte[10], 0, 10)); + Assert.Throws(() => context.Response.Body.Flush()); + + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal(new Version(1, 1), response.Version); + IEnumerable ignored; + Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length"); + Assert.True(response.Headers.TransferEncodingChunked.Value, "Chunked"); + Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + } + } + [ConditionalFact] public async Task ResponseBody_WriteNoHeaders_DefaultsToChunked() { @@ -24,6 +59,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { var responseTask = SendRequestAsync(address); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Body.Write(new byte[10], 0, 10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); @@ -45,6 +81,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { + server.Options.AllowSynchronousIO = true; var responseTask = SendRequestAsync(address); var context = await server.AcceptAsync(Utilities.DefaultTimeout); @@ -95,6 +132,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { var responseTask = SendRequestAsync(address); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 30 "; var stream = context.Response.Body; @@ -181,6 +219,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { var responseTask = SendRequestAsync(address); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 10 "; context.Response.Body.Write(new byte[10], 0, 10); @@ -206,6 +245,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { var responseTask = SendRequestAsync(address); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Body.Write(new byte[10], 0, 0); Assert.True(context.Response.HasStarted); @@ -380,6 +420,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener using (var server = Utilities.CreateHttpServer(out address)) { server.Options.ThrowWriteExceptions = true; + server.Options.AllowSynchronousIO = true; var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); @@ -444,6 +485,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var cts = new CancellationTokenSource(); var responseTask = SendRequestAsync(address, cts.Token); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); @@ -555,6 +597,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener string address; using (var server = Utilities.CreateHttpServer(out address)) { + server.Options.AllowSynchronousIO = true; RequestContext context; using (var client = new HttpClient()) { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs index 1505fd1dba..1ed657515e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs @@ -324,7 +324,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 10; context.Response.CacheTtl = TimeSpan.FromSeconds(10); - context.Response.Body.Write(new byte[10], 0, 10); + await context.Response.Body.WriteAsync(new byte[10], 0, 10); // Http.Sys will add this for us Assert.Null(context.Response.ContentLength); context.Dispose(); @@ -381,6 +381,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { var responseTask = SendRequestAsync(address); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache @@ -418,8 +419,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.CacheTtl = TimeSpan.FromSeconds(10); - context.Response.Body.Write(new byte[10], 0, 10); - context.Response.Body.Flush(); + await context.Response.Body.WriteAsync(new byte[10], 0, 10); + await context.Response.Body.FlushAsync(); context.Dispose(); var response = await responseTask; @@ -453,7 +454,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 10; context.Response.CacheTtl = TimeSpan.FromSeconds(10); - context.Response.Body.Write(new byte[10], 0, 10); + await context.Response.Body.WriteAsync(new byte[10], 0, 10); // Http.Sys will add this for us Assert.Null(context.Response.ContentLength); context.Dispose(); @@ -999,7 +1000,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.Headers["content-range"] = "bytes 0-10/100"; context.Response.ContentLength = 11; context.Response.CacheTtl = TimeSpan.FromSeconds(10); - context.Response.Body.Write(new byte[100], 0, 11); + await context.Response.Body.WriteAsync(new byte[100], 0, 11); context.Dispose(); var response = await responseTask; @@ -1016,7 +1017,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.Headers["content-range"] = "bytes 0-10/100"; context.Response.ContentLength = 11; context.Response.CacheTtl = TimeSpan.FromSeconds(10); - context.Response.Body.Write(new byte[100], 0, 11); + await context.Response.Body.WriteAsync(new byte[100], 0, 11); context.Dispose(); response = await responseTask; @@ -1041,7 +1042,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 100; context.Response.CacheTtl = TimeSpan.FromSeconds(10); - context.Response.Body.Write(new byte[100], 0, 100); + await context.Response.Body.WriteAsync(new byte[100], 0, 100); context.Dispose(); var response = await responseTask; @@ -1071,7 +1072,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache context.Response.ContentLength = 100; context.Response.CacheTtl = TimeSpan.FromSeconds(10); - context.Response.Body.Write(new byte[100], 0, 100); + await context.Response.Body.WriteAsync(new byte[100], 0, 100); context.Dispose(); var response = await responseTask; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 982024730e..66ecbd7e19 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -390,6 +390,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { Task responseTask = SendRequestAsync(address); + server.Options.AllowSynchronousIO = true; var context = await server.AcceptAsync(Utilities.DefaultTimeout); var responseHeaders = context.Response.Headers; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index cbd7000614..e12488f13e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -42,10 +42,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.ContentLength = 11; - using (var writer = new StreamWriter(context.Response.Body)) - { - writer.Write("Hello World"); - } + var writer = new StreamWriter(context.Response.Body); + await writer.WriteAsync("Hello World"); + await writer.FlushAsync(); string response = await responseTask; Assert.Equal("Hello World", response); @@ -61,13 +60,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var responseTask = SendRequestAsync(address, "Hello World"); var context = await server.AcceptAsync(Utilities.DefaultTimeout); - string input = new StreamReader(context.Request.Body).ReadToEnd(); + var input = await new StreamReader(context.Request.Body).ReadToEndAsync(); Assert.Equal("Hello World", input); context.Response.ContentLength = 11; - using (var writer = new StreamWriter(context.Response.Body)) - { - writer.Write("Hello World"); - } + var writer = new StreamWriter(context.Response.Body); + await writer.WriteAsync("Hello World"); + await writer.FlushAsync(); var response = await responseTask; Assert.Equal("Hello World", response); @@ -218,10 +216,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context.Response.Headers["Connection"] = "close"; context.Response.ContentLength = 11; - using (var writer = new StreamWriter(context.Response.Body)) - { - writer.Write("Hello World"); - } + var writer = new StreamWriter(context.Response.Body); + await writer.WriteAsync("Hello World"); + await writer.FlushAsync(); Assert.True(canceled.WaitOne(interval), "Disconnected"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs index 48421ddcaa..a37daceb04 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.True(feature.IsReadOnly); Assert.Null(feature.MaxRequestBodySize); Assert.Throws(() => feature.MaxRequestBodySize = 12); - Assert.Equal(15, stream.Read(new byte[15], 0, 15)); + Assert.Equal(15, await stream.ReadAsync(new byte[15], 0, 15)); upgraded = true; waitHandle.Set(); })) @@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys using (Stream stream = await SendOpaqueRequestAsync("GET", address)) { stream.Write(new byte[15], 0, 15); - Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(1)), "Timed out"); + Assert.True(waitHandle.WaitOne(TimeSpan.FromSeconds(10)), "Timed out"); Assert.True(upgraded.HasValue, "Upgraded not set"); Assert.True(upgraded.Value, "Upgrade failed"); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs index ed835f345f..ebc0fa9f98 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs @@ -21,6 +21,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; var feature = httpContext.Features.Get(); Assert.NotNull(feature); Assert.False(feature.IsReadOnly); @@ -86,6 +87,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 11, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; var feature = httpContext.Features.Get(); Assert.NotNull(feature); Assert.False(feature.IsReadOnly); @@ -151,6 +153,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; var feature = httpContext.Features.Get(); Assert.NotNull(feature); Assert.False(feature.IsReadOnly); @@ -220,6 +223,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; var feature = httpContext.Features.Get(); Assert.NotNull(feature); Assert.False(feature.IsReadOnly); @@ -290,6 +294,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, options => options.MaxRequestBodySize = 10, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; var feature = httpContext.Features.Get(); Assert.NotNull(feature); Assert.False(feature.IsReadOnly); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs index 23c7c56be1..1b87920103 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs @@ -9,6 +9,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -23,6 +24,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys using (Utilities.CreateHttpServer(out address, httpContext => { byte[] input = new byte[100]; + httpContext.Features.Get().AllowSynchronousIO = true; int read = httpContext.Request.Body.Read(input, 0, input.Length); httpContext.Response.ContentLength = read; httpContext.Response.Body.Write(input, 0, read); @@ -75,6 +77,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; byte[] input = new byte[100]; Assert.Throws("buffer", () => httpContext.Request.Body.Read(null, 0, 1)); Assert.Throws("offset", () => httpContext.Request.Body.Read(input, -1, 1)); @@ -99,6 +102,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys using (Utilities.CreateHttpServer(out address, httpContext => { byte[] input = new byte[10]; + httpContext.Features.Get().AllowSynchronousIO = true; int read = httpContext.Request.Body.Read(input, 0, input.Length); Assert.Equal(5, read); content.Block.Release(); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs index 18dee99410..4c3089edea 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs @@ -9,6 +9,7 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -22,6 +23,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; httpContext.Response.Body.Write(new byte[10], 0, 10); return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) @@ -42,6 +44,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, async httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; httpContext.Response.Body.Write(new byte[10], 0, 10); await httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); await httpContext.Response.Body.FlushAsync(); @@ -85,6 +88,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, async httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; httpContext.Response.Headers["Content-lenGth"] = " 30 "; Stream stream = httpContext.Response.Body; stream.EndWrite(stream.BeginWrite(new byte[10], 0, 10, null, null)); @@ -124,8 +128,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys using (Utilities.CreateHttpServer(out address, httpContext => { httpContext.Response.Headers["Content-lenGth"] = " 20 "; - httpContext.Response.Body.Write(new byte[5], 0, 5); - return Task.FromResult(0); + return httpContext.Response.Body.WriteAsync(new byte[5], 0, 5); })) { Assert.Throws(() => SendRequestAsync(address).Result); @@ -137,13 +140,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var completed = false; string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (Utilities.CreateHttpServer(out address, async httpContext => { httpContext.Response.Headers["Content-lenGth"] = " 10 "; - httpContext.Response.Body.Write(new byte[5], 0, 5); - Assert.Throws(() => httpContext.Response.Body.Write(new byte[6], 0, 6)); + await httpContext.Response.Body.WriteAsync(new byte[5], 0, 5); + await Assert.ThrowsAsync(() => + httpContext.Response.Body.WriteAsync(new byte[6], 0, 6)); completed = true; - return Task.FromResult(0); })) { await Assert.ThrowsAsync(() => SendRequestAsync(address)); @@ -161,6 +164,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { try { + httpContext.Features.Get().AllowSynchronousIO = true; httpContext.Response.Headers["Content-lenGth"] = " 10 "; httpContext.Response.Body.Write(new byte[10], 0, 10); httpContext.Response.Body.Write(new byte[9], 0, 9); @@ -197,6 +201,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; httpContext.Response.OnStarting(state => { onStartingCalled = true; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index 96b112ae59..0b169e906e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -130,8 +130,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders["Connection"] = new string[] { "Close" }; - httpContext.Response.Body.Flush(); // Http.Sys adds the Content-Length: header for us if we don't flush - return Task.FromResult(0); + return httpContext.Response.Body.FlushAsync(); // Http.Sys adds the Content-Length: header for us if we don't flush })) { HttpResponseMessage response = await SendRequestAsync(address); @@ -204,6 +203,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys string address; using (Utilities.CreateHttpServer(out address, httpContext => { + httpContext.Features.Get().AllowSynchronousIO = true; var responseInfo = httpContext.Features.Get(); var responseHeaders = responseInfo.Headers; responseHeaders.Add("Custom1", new string[] { "value1a", "value1b" }); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 4d8129d7f4..01224b2bc6 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -53,12 +53,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys public async Task Server_EchoHelloWorld_Success() { string address; - using (Utilities.CreateHttpServer(out address, httpContext => + using (Utilities.CreateHttpServer(out address, async httpContext => { - string input = new StreamReader(httpContext.Request.Body).ReadToEnd(); + var input = await new StreamReader(httpContext.Request.Body).ReadToEndAsync(); Assert.Equal("Hello World", input); httpContext.Response.ContentLength = 11; - return httpContext.Response.WriteAsync("Hello World"); + await httpContext.Response.WriteAsync("Hello World"); })) { string response = await SendRequestAsync(address, "Hello World"); From e46a9d4bc425204b7e0b478964f3d15afbebb106 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 6 Jul 2017 10:37:44 -0700 Subject: [PATCH 510/597] React to aspnet/BuildTools#293 [ci skip] --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5265f399a5..fd1d249b8d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.0.0-* 4.4.0-* - 2.1.0-* + 2.0.1-* 2.0.0-* 2.0.0-* 2.0.0-* From 856fc7f70ca285e8d4fb100ec555bc67e6f68588 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 6 Jul 2017 12:13:46 -0700 Subject: [PATCH 511/597] Set "TreatWarningsAsErrors" before NuGet restore * Ensures our build stays clean of NuGet warnings --- build/common.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/common.props b/build/common.props index f336a03553..5792d5cae4 100644 --- a/build/common.props +++ b/build/common.props @@ -10,6 +10,7 @@ true true $(VersionSuffix)-$(BuildNumber) + true From d6d7a8f9b6976caba26b72c08a2ba855ef183614 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 6 Jul 2017 15:08:21 -0700 Subject: [PATCH 512/597] Update version suffix for 2.0.0 RTM release --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index a327eefab8..4c3cc829ad 100644 --- a/version.props +++ b/version.props @@ -2,6 +2,6 @@ 2.0.0 - preview3 + rtm \ No newline at end of file From 5ff977625f0cea3ff209945c2881b3b581228ab6 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 6 Jul 2017 15:26:12 -0700 Subject: [PATCH 513/597] Remove NETSTandard.Library.NETFramework --- build/common.props | 4 ---- samples/HotAddSample/HotAddSample.csproj | 4 ---- samples/SelfHostServer/SelfHostServer.csproj | 4 ---- 3 files changed, 12 deletions(-) diff --git a/build/common.props b/build/common.props index 5792d5cae4..ad57d1fd2e 100644 --- a/build/common.props +++ b/build/common.props @@ -17,8 +17,4 @@ - - - - diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index a02b6162da..6620ed7c5d 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -12,8 +12,4 @@ - - - - diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index a02b6162da..6620ed7c5d 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -12,8 +12,4 @@ - - - - From 66221b7f5c133e7fa4b9d36d81cb1d43f5b43b61 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 10 Jul 2017 11:43:10 -0700 Subject: [PATCH 514/597] Branching for 2.0.0 rtm --- NuGet.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..37f0d27ea0 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,7 +2,7 @@ - + From e9153fd174f3758231c08774e26915b4e3ab5a6e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 10 Jul 2017 11:57:57 -0700 Subject: [PATCH 515/597] Updating KoreBuild branch --- build.ps1 | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..1785334385 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index b0bcadb579..5e27ed8efb 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/2.0.0.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 290f57427efd542a341fd2e8f518cf7172db3fa7 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 7 Jul 2017 14:55:52 -0700 Subject: [PATCH 516/597] Skip first time experience on Appveyor --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1041615c68..31efd8196f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -init: +init: - git config --global core.autocrlf true branches: only: @@ -9,6 +9,10 @@ branches: build_script: - ps: .\build.ps1 clone_depth: 1 +environment: + global: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 test: off deploy: off os: Visual Studio 2017 From 9c1417d568fe558dde54cb226d2e03abf4e12b3d Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 21 Jul 2017 12:59:36 -0700 Subject: [PATCH 517/597] 2.0.0-rtm to 2.1.0-preview1 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index 4c3cc829ad..b32d3db0a8 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - 2.0.0 - rtm + 2.1.0 + preview1 \ No newline at end of file From 015de501ad3dd1056a68b9460667265deb5d6454 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 24 Jul 2017 17:56:26 -0700 Subject: [PATCH 518/597] Set AspNetCoreVersion --- build/dependencies.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index fd1d249b8d..833d909a0d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,6 +1,6 @@ - + - 2.0.0-* + 2.1.0-* 4.4.0-* 2.0.1-* 2.0.0-* From a8da54012e716a14907471eb03cc3e1828ae6860 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 25 Jul 2017 15:13:26 -0700 Subject: [PATCH 519/597] Updating to InternalAspNetCoreSdkVersion 2.1.1-* --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 833d909a0d..3c71bd378d 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,7 +2,7 @@ 2.1.0-* 4.4.0-* - 2.0.1-* + 2.1.1-* 2.0.0-* 2.0.0-* 2.0.0-* From d7357f09c2a6c73bf3ce4c3d420c3e1a098b0361 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 25 Jul 2017 16:32:22 -0700 Subject: [PATCH 520/597] Update bootstrappers to use the compiled version of KoreBuild [ci skip] --- .gitignore | 2 + HttpSysServer.sln | 2 +- build.cmd | 2 +- build.ps1 | 218 +++++++++++++++++++++++++--------- build.sh | 224 +++++++++++++++++++++++++++++------ build/common.props | 2 +- version.props => version.xml | 5 +- 7 files changed, 359 insertions(+), 96 deletions(-) rename version.props => version.xml (51%) diff --git a/.gitignore b/.gitignore index e51ec46f9b..94caeb71e6 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,5 @@ project.lock.json .vscode/ .build/ .testPublish/ +global.json +korebuild-lock.txt diff --git a/HttpSysServer.sln b/HttpSysServer.sln index 0663cc30a2..dcf802bb78 100644 --- a/HttpSysServer.sln +++ b/HttpSysServer.sln @@ -16,7 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution build.ps1 = build.ps1 build.sh = build.sh NuGet.config = NuGet.config - version.props = version.props + version.xml = version.xml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}" diff --git a/build.cmd b/build.cmd index 7d4894cb4a..b6c8d24864 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/build.ps1 index 5bf0e2c113..d5eb4d5cf2 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,67 +1,177 @@ -$ErrorActionPreference = "Stop" +#!/usr/bin/env powershell +#requires -version 4 -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) -{ - while($true) - { - try - { - Invoke-WebRequest $url -OutFile $downloadLocation - break - } - catch - { - $exceptionMessage = $_.Exception.Message - Write-Host "Failed to download '$url': $exceptionMessage" - if ($retries -gt 0) { - $retries-- - Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" - Start-Sleep -Seconds 10 +<# +.SYNOPSIS +Build this repository +.DESCRIPTION +Downloads korebuild if required. Then builds the repository. + +.PARAMETER Path +The folder to build. Defaults to the folder containing this script. + +.PARAMETER Channel +The channel of KoreBuild to download. Overrides the value from the config file. + +.PARAMETER DotNetHome +The directory where .NET Core tools will be stored. + +.PARAMETER ToolsSource +The base url where build tools can be downloaded. Overrides the value from the config file. + +.PARAMETER Update +Updates KoreBuild to the latest version even if a lock file is present. + +.PARAMETER ConfigFile +The path to the configuration file that stores values. Defaults to version.xml. + +.PARAMETER MSBuildArgs +Arguments to be passed to MSBuild + +.NOTES +This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. +When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. + +The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well. + +.EXAMPLE +Example config file: +```xml + + + + dev + https://aspnetcore.blob.core.windows.net/buildtools + + +``` +#> +[CmdletBinding(PositionalBinding = $false)] +param( + [string]$Path = $PSScriptRoot, + [Alias('c')] + [string]$Channel, + [Alias('d')] + [string]$DotNetHome, + [Alias('s')] + [string]$ToolsSource, + [Alias('u')] + [switch]$Update, + [string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'), + [Parameter(ValueFromRemainingArguments = $true)] + [string[]]$MSBuildArgs +) + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +# +# Functions +# + +function Get-KoreBuild { + + $lockFile = Join-Path $Path 'korebuild-lock.txt' + + if (!(Test-Path $lockFile) -or $Update) { + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile + } + + $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 + if (!$version) { + Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" + } + $version = $version.TrimStart('version:').Trim() + $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) + + if (!(Test-Path $korebuildPath)) { + Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" + New-Item -ItemType Directory -Path $korebuildPath | Out-Null + $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" + + try { + $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" + Get-RemoteFile $remotePath $tmpfile + if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { + # Use built-in commands where possible as they are cross-plat compatible + Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath } - else - { - $exception = $_.Exception - throw $exception + else { + # Fallback to old approach for old installations of PowerShell + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) } } + catch { + Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore + throw + } + finally { + Remove-Item $tmpfile -ErrorAction Ignore + } } + + return $korebuildPath } -cd $PSScriptRoot - -$repoFolder = $PSScriptRoot -$env:REPO_FOLDER = $repoFolder - -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if ($env:KOREBUILD_ZIP) -{ - $koreBuildZip=$env:KOREBUILD_ZIP +function Join-Paths([string]$path, [string[]]$childPaths) { + $childPaths | ForEach-Object { $path = Join-Path $path $_ } + return $path } -$buildFolder = ".build" -$buildFile="$buildFolder\KoreBuild.ps1" - -if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - - $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() - New-Item -Path "$tempFolder" -Type directory | Out-Null - - $localZipFile="$tempFolder\korebuild.zip" - - DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 - - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - - New-Item -Path "$buildFolder" -Type directory | Out-Null - copy-item "$tempFolder\**\build\*" $buildFolder -Recurse - - # Cleanup - if (Test-Path $tempFolder) { - Remove-Item -Recurse -Force $tempFolder +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { + if ($RemotePath -notlike 'http*') { + Copy-Item $RemotePath $LocalPath + return } + + $retries = 10 + while ($retries -gt 0) { + $retries -= 1 + try { + Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath + return + } + catch { + Write-Verbose "Request failed. $retries retries remaining" + } + } + + Write-Error "Download failed: '$RemotePath'." } -&"$buildFile" @args +# +# Main +# + +# Load configuration or set defaults + +if (Test-Path $ConfigFile) { + [xml] $config = Get-Content $ConfigFile + if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' } + if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' } +} + +if (!$DotNetHome) { + $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` + elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` + elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` + else { Join-Path $PSScriptRoot '.dotnet'} +} + +if (!$Channel) { $Channel = 'dev' } +if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } + +# Execute + +$korebuildPath = Get-KoreBuild +Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') + +try { + Install-Tools $ToolsSource $DotNetHome + Invoke-RepositoryBuild $Path @MSBuildArgs +} +finally { + Remove-Module 'KoreBuild' -ErrorAction Ignore +} diff --git a/build.sh b/build.sh index b0bcadb579..ab590e62f1 100755 --- a/build.sh +++ b/build.sh @@ -1,46 +1,196 @@ #!/usr/bin/env bash -repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if [ ! -z $KOREBUILD_ZIP ]; then - koreBuildZip=$KOREBUILD_ZIP -fi +set -euo pipefail -buildFolder=".build" -buildFile="$buildFolder/KoreBuild.sh" +# +# variables +# -if test ! -d $buildFolder; then - echo "Downloading KoreBuild from $koreBuildZip" +RESET="\033[0m" +RED="\033[0;31m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet" +config_file="$DIR/version.xml" +verbose=false +update=false +repo_path="$DIR" +channel='' +tools_source='' - tempFolder="/tmp/KoreBuild-$(uuidgen)" - mkdir $tempFolder +# +# Functions +# +__usage() { + echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file TThe path to the configuration file that stores values. Defaults to version.xml." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source The base url where build tools can be downloaded. Overrides the value from the config file." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - localZipFile="$tempFolder/korebuild.zip" - - retries=6 - until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) - do - echo "Failed to download '$koreBuildZip'" - if [ "$retries" -le 0 ]; then - exit 1 - fi - retries=$((retries - 1)) - echo "Waiting 10 seconds before retrying. Retries left: $retries" - sleep 10s - done - - unzip -q -d $tempFolder $localZipFile - - mkdir $buildFolder - cp -r $tempFolder/**/build/** $buildFolder - - chmod +x $buildFile - - # Cleanup - if test -d $tempFolder; then - rm -rf $tempFolder + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 fi +} + +get_korebuild() { + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f $lock_file ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file + fi + local version="$(grep 'version:*' -m 1 $lock_file)" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file $remote_path $tmpfile; then + unzip -q -d "$korebuild_path" $tmpfile + fi + rm $tmpfile || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}$@${RESET}" 1>&2 +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + + if [[ "$remote_path" != 'http'* ]]; then + cp $remote_path $local_path + return 0 + fi + + failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O $local_path $remote_path || failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;} + +# +# main +# + +while [[ $# > 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel=${1:-} + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME=${1:-} + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 fi -$buildFile -r $repoFolder "$@" +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +if [ -f $config_file ]; then + comment=false + while __read_dom; do + if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi + if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi + if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi + if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi + done < $config_file +fi + +[ -z "$channel" ] && channel='dev' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +install_tools "$tools_source" "$DOTNET_HOME" +invoke_repository_build "$repo_path" $@ diff --git a/build/common.props b/build/common.props index ad57d1fd2e..d893ee6ec6 100644 --- a/build/common.props +++ b/build/common.props @@ -1,6 +1,6 @@ - + Microsoft ASP.NET Core diff --git a/version.props b/version.xml similarity index 51% rename from version.props rename to version.xml index b32d3db0a8..3c05022b7d 100644 --- a/version.props +++ b/version.xml @@ -1,7 +1,8 @@ - + + dev 2.1.0 preview1 - \ No newline at end of file + From 33b6ed79a90bfa60eadef0b9033077ebf542cd6c Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 26 Jul 2017 10:27:42 -0700 Subject: [PATCH 521/597] Fix syntax warning when running build.sh on older versions of bash [ci skip] --- build.sh | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/build.sh b/build.sh index ab590e62f1..5568c6182a 100755 --- a/build.sh +++ b/build.sh @@ -10,7 +10,7 @@ RESET="\033[0m" RED="\033[0;31m" MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" config_file="$DIR/version.xml" verbose=false update=false @@ -22,7 +22,7 @@ tools_source='' # Functions # __usage() { - echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] ...]" + echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...]" echo "" echo "Arguments:" echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." @@ -46,16 +46,17 @@ __usage() { } get_korebuild() { + local version local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f $lock_file ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" fi - local version="$(grep 'version:*' -m 1 $lock_file)" + version="$(grep 'version:*' -m 1 "$lock_file")" if [[ "$version" == '' ]]; then __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" return 1 fi - version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" { @@ -64,10 +65,10 @@ get_korebuild() { local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file $remote_path $tmpfile; then - unzip -q -d "$korebuild_path" $tmpfile + if __get_remote_file "$remote_path" "$tmpfile"; then + unzip -q -d "$korebuild_path" "$tmpfile" fi - rm $tmpfile || true + rm "$tmpfile" || true fi source "$korebuild_path/KoreBuild.sh" @@ -81,7 +82,7 @@ get_korebuild() { } __error() { - echo -e "${RED}$@${RESET}" 1>&2 + echo -e "${RED}$*${RESET}" 1>&2 } __machine_has() { @@ -94,18 +95,18 @@ __get_remote_file() { local local_path=$2 if [[ "$remote_path" != 'http'* ]]; then - cp $remote_path $local_path + cp "$remote_path" "$local_path" return 0 fi failed=false if __machine_has wget; then - wget --tries 10 --quiet -O $local_path $remote_path || failed=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false - curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ]; then @@ -114,13 +115,13 @@ __get_remote_file() { fi } -__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;} +__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;} # # main # -while [[ $# > 0 ]]; do +while [[ $# -gt 0 ]]; do case $1 in -\?|-h|--help) __usage --no-exit @@ -128,7 +129,7 @@ while [[ $# > 0 ]]; do ;; -c|--channel|-Channel) shift - channel=${1:-} + channel="${1:-}" [ -z "$channel" ] && __usage ;; --config-file|-ConfigFile) @@ -138,7 +139,7 @@ while [[ $# > 0 ]]; do ;; -d|--dotnet-home|-DotNetHome) shift - DOTNET_HOME=${1:-} + DOTNET_HOME="${1:-}" [ -z "$DOTNET_HOME" ] && __usage ;; --path|-Path) @@ -178,14 +179,14 @@ if ! __machine_has curl && ! __machine_has wget; then exit 1 fi -if [ -f $config_file ]; then +if [ -f "$config_file" ]; then comment=false while __read_dom; do if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi - done < $config_file + done < "$config_file" fi [ -z "$channel" ] && channel='dev' @@ -193,4 +194,4 @@ fi get_korebuild install_tools "$tools_source" "$DOTNET_HOME" -invoke_repository_build "$repo_path" $@ +invoke_repository_build "$repo_path" "$@" From 995ed3e294c07453d420cce862d86b1e1d0ee7f4 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Aug 2017 12:44:45 -0700 Subject: [PATCH 522/597] Update __get_remote_file logic --- build.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 5568c6182a..8eace4c20d 100755 --- a/build.sh +++ b/build.sh @@ -99,17 +99,16 @@ __get_remote_file() { return 0 fi - failed=false + local succeeded=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" && succeeded=true fi - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + if [ "$succeeded" = false ] && __machine_has curl; then + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" && succeeded=true fi - if [ "$failed" = true ]; then + if [ "$succeeded" = false ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi From 17852e521768c2a1e2626d6d67e7300fe2e5c201 Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 2 Aug 2017 14:32:04 -0700 Subject: [PATCH 523/597] Ensure fallback to curl after failed wget --- build.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 8eace4c20d..11cdbe5504 100755 --- a/build.sh +++ b/build.sh @@ -99,16 +99,19 @@ __get_remote_file() { return 0 fi - local succeeded=false + local failed=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" && succeeded=true + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + else + failed=true fi - if [ "$succeeded" = false ] && __machine_has curl; then - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" && succeeded=true + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi - if [ "$succeeded" = false ]; then + if [ "$failed" = true ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi From dc8d1d078827ad733afc668ac6fe2c716545969f Mon Sep 17 00:00:00 2001 From: John Luo Date: Wed, 16 Aug 2017 19:30:36 -0700 Subject: [PATCH 524/597] Do not block on async calls --- .../Listener/ResponseSendFileTests.cs | 2 +- .../OpaqueUpgradeTests.cs | 2 +- .../ResponseBodyTests.cs | 4 ++-- .../ResponseSendFileTests.cs | 2 +- .../ServerTests.cs | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index f8d94e1087..fb0b739295 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); Assert.Equal(FileLength.ToString(), contentLength.First()); Assert.Null(response.Headers.TransferEncodingChunked); - Assert.Equal(FileLength, response.Content.ReadAsByteArrayAsync().Result.Length); + Assert.Equal(FileLength, (await response.Content.ReadAsByteArrayAsync()).Length); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs index a37daceb04..c0fdda0dd2 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(200, (int)response.StatusCode); Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); Assert.Equal(0, response.Content.Headers.ContentLength); - Assert.Equal(string.Empty, response.Content.ReadAsStringAsync().Result); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs index 4c3089edea..a42071b342 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public void ResponseBody_WriteContentLengthNotEnoughWritten_Throws() + public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Throws() { string address; using (Utilities.CreateHttpServer(out address, httpContext => @@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys return httpContext.Response.Body.WriteAsync(new byte[5], 0, 5); })) { - Assert.Throws(() => SendRequestAsync(address).Result); + await Assert.ThrowsAsync(async () => await SendRequestAsync(address)); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs index 09fd9c3b86..02117c6b53 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs @@ -274,7 +274,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); Assert.Equal(FileLength.ToString(), contentLength.First()); Assert.Null(response.Headers.TransferEncodingChunked); - Assert.Equal(FileLength, response.Content.ReadAsByteArrayAsync().Result.Length); + Assert.Equal(FileLength, (await response.Content.ReadAsByteArrayAsync()).Length); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 01224b2bc6..9e5bc9e444 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - public void Server_AppException_ClientReset() + public async Task Server_AppException_ClientReset() { string address; using (Utilities.CreateHttpServer(out address, httpContext => @@ -144,11 +144,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys })) { Task requestTask = SendRequestAsync(address); - Assert.Throws(() => requestTask.Result); + await Assert.ThrowsAsync(async () => await requestTask); // Do it again to make sure the server didn't crash requestTask = SendRequestAsync(address); - Assert.Throws(() => requestTask.Result); + await Assert.ThrowsAsync(async () => await requestTask); } } From c36b18d80e39854248b32c83d29fcbed7777006e Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 22 Aug 2017 15:43:31 -0700 Subject: [PATCH 525/597] Upgrade to xunit 2.3.0-beta4 --- build/dependencies.props | 4 ++-- .../AuthenticationTests.cs | 16 ++++++---------- .../Listener/AuthenticationTests.cs | 2 +- .../Listener/ResponseCachingTests.cs | 4 ++-- .../Listener/ResponseHeaderTests.cs | 18 +++++++++--------- .../Listener/ResponseSendFileTests.cs | 4 ++-- .../ResponseHeaderTests.cs | 6 +++--- .../ResponseSendFileTests.cs | 4 ++-- 8 files changed, 27 insertions(+), 31 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3c71bd378d..1235e00530 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -6,7 +6,7 @@ 2.0.0-* 2.0.0-* 2.0.0-* - 15.3.0-* - 2.3.0-beta2-* + 15.3.0 + 2.3.0-beta4-build3742 diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index ebb092b746..87a712fa24 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + Assert.Empty(response.Headers.WwwAuthenticate); } } @@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + Assert.Empty(response.Headers.WwwAuthenticate); } } @@ -306,12 +306,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] - [InlineData(AuthenticationSchemes.Negotiate)] - [InlineData(AuthenticationSchemes.NTLM)] - // [InlineData(AuthenticationSchemes.Digest)] - [InlineData(AuthenticationSchemes.Basic)] - public async Task AuthTypes_Forbid_Forbidden(AuthenticationSchemes authType) + [ConditionalFact] + public async Task AuthTypes_Forbid_Forbidden() { var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; using (var server = Utilities.CreateDynamicHost(authTypes, AllowAnoymous, out var address, httpContext => @@ -324,7 +320,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var response = await SendRequestAsync(address); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); - Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + Assert.Empty(response.Headers.WwwAuthenticate); } } @@ -345,7 +341,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { var response = await SendRequestAsync(address, useDefaultCredentials: true); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); - Assert.Equal(1, response.Headers.WwwAuthenticate.Count); + Assert.Single(response.Headers.WwwAuthenticate); Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.First().Scheme); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs index 13c75bbfd2..ac7cb7056e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var response = await responseTask; Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(0, response.Headers.WwwAuthenticate.Count); + Assert.Empty(response.Headers.WwwAuthenticate); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs index 1ed657515e..b3bc680e72 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs @@ -1083,7 +1083,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener response = await SendRequestAsync(address, "GET", "Range", "bytes=0-10,15-20"); Assert.Equal(206, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); - Assert.True(response.Content.Headers.GetValues("content-type").First().StartsWith("multipart/byteranges;")); + Assert.StartsWith("multipart/byteranges;", response.Content.Headers.GetValues("content-type").First()); } } @@ -1145,7 +1145,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener response = await SendRequestAsync(address, "GET", "Range", "bytes=0-" + (rangeLength - 1) + "," + rangeLength + "-" + (rangeLength + rangeLength - 1), HttpCompletionOption.ResponseHeadersRead); Assert.Equal(206, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); - Assert.True(response.Content.Headers.GetValues("content-type").First().StartsWith("multipart/byteranges;")); + Assert.StartsWith("multipart/byteranges;", response.Content.Headers.GetValues("content-type").First()); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 66ecbd7e19..86b377e7e3 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.False(response.Headers.TransferEncodingChunked.HasValue); Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); - Assert.Equal(1, response.Content.Headers.Count()); + Assert.Single(response.Content.Headers); Assert.Equal(0, response.Content.Headers.ContentLength); } } @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(response.Headers.ConnectionClose.Value); Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); - Assert.Equal(1, response.Content.Headers.Count()); + Assert.Single(response.Content.Headers); Assert.Equal(0, response.Content.Headers.ContentLength); } } @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); - Assert.Equal(0, response.Content.Headers.Count()); + Assert.Empty(response.Content.Headers); // Send a second request to check that the connection wasn't corrupted. responseTask = SendHeadRequestAsync(address); @@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); - Assert.Equal(0, response.Content.Headers.Count()); + Assert.Empty(response.Content.Headers); // Send a second request to check that the connection wasn't corrupted. responseTask = SendHeadRequestAsync(address); @@ -143,7 +143,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.False(response.Headers.TransferEncodingChunked.HasValue); Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); - Assert.Equal(1, response.Content.Headers.Count()); + Assert.Single(response.Content.Headers); Assert.Equal(20, response.Content.Headers.ContentLength); // Send a second request to check that the connection wasn't corrupted. @@ -173,7 +173,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); - Assert.Equal(0, response.Content.Headers.Count()); + Assert.Empty(response.Content.Headers); } } @@ -196,7 +196,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); Assert.False(response.Content.Headers.Contains("Content-Length")); - Assert.Equal(0, response.Content.Headers.Count()); + Assert.Empty(response.Content.Headers); // Send a second request to check that the connection wasn't corrupted. responseTask = SendHeadRequestAsync(address); @@ -414,7 +414,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(2, response.Headers.GetValues("Custom1").Count()); Assert.Equal("value1a", response.Headers.GetValues("Custom1").First()); Assert.Equal("value1b", response.Headers.GetValues("Custom1").Skip(1).First()); - Assert.Equal(1, response.Headers.GetValues("Custom2").Count()); + Assert.Single(response.Headers.GetValues("Custom2")); Assert.Equal("value2a, value2b", response.Headers.GetValues("Custom2").First()); } } @@ -450,7 +450,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(2, response.Headers.GetValues("Custom1").Count()); Assert.Equal("value1a", response.Headers.GetValues("Custom1").First()); Assert.Equal("value1b", response.Headers.GetValues("Custom1").Skip(1).First()); - Assert.Equal(1, response.Headers.GetValues("Custom2").Count()); + Assert.Single(response.Headers.GetValues("Custom2")); Assert.Equal("value2a, value2b", response.Headers.GetValues("Custom2").First()); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index fb0b739295..a24bd3d4ac 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); Assert.True(response.Headers.TransferEncodingChunked.Value); - Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); + Assert.Empty((await response.Content.ReadAsByteArrayAsync())); } } @@ -299,7 +299,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); Assert.Equal("0", contentLength.First()); Assert.Null(response.Headers.TransferEncodingChunked); - Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); + Assert.Empty((await response.Content.ReadAsByteArrayAsync())); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index 0b169e906e..bec341b50f 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(response.Headers.TransferEncodingChunked.HasValue); Assert.True(response.Headers.Date.HasValue); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers.Server.ToString()); - Assert.Equal(1, response.Content.Headers.Count()); + Assert.Single(response.Content.Headers); Assert.Equal(0, response.Content.Headers.ContentLength); } } @@ -224,7 +224,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(2, response.Headers.GetValues("Custom1").Count()); Assert.Equal("value1a", response.Headers.GetValues("Custom1").First()); Assert.Equal("value1b", response.Headers.GetValues("Custom1").Skip(1).First()); - Assert.Equal(1, response.Headers.GetValues("Custom2").Count()); + Assert.Single(response.Headers.GetValues("Custom2")); Assert.Equal("value2a, value2b", response.Headers.GetValues("Custom2").First()); } } @@ -254,7 +254,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(2, response.Headers.GetValues("Custom1").Count()); Assert.Equal("value1a", response.Headers.GetValues("Custom1").First()); Assert.Equal("value1b", response.Headers.GetValues("Custom1").Skip(1).First()); - Assert.Equal(1, response.Headers.GetValues("Custom2").Count()); + Assert.Single(response.Headers.GetValues("Custom2")); Assert.Equal("value2a, value2b", response.Headers.GetValues("Custom2").First()); } } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs index 02117c6b53..d3a8c5e5d0 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs @@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys IEnumerable contentLength; Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); Assert.True(response.Headers.TransferEncodingChunked.Value); - Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); + Assert.Empty((await response.Content.ReadAsByteArrayAsync())); } } @@ -316,7 +316,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length"); Assert.Equal("0", contentLength.First()); Assert.Null(response.Headers.TransferEncodingChunked); - Assert.Equal(0, (await response.Content.ReadAsByteArrayAsync()).Length); + Assert.Empty((await response.Content.ReadAsByteArrayAsync())); } } From d72175a84649f69bba7452febf1d301cfe27470d Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Wed, 23 Aug 2017 12:08:43 -0700 Subject: [PATCH 526/597] Make StopAsync multi-thread safe (#377). --- .../MessagePump.cs | 65 ++++-- .../ServerTests.cs | 189 ++++++++++++++++++ 2 files changed, 234 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 82e6a03039..53330c6f1c 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -25,9 +25,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys private int _acceptorCounts; private Action _processRequest; - private bool _stopping; + private volatile int _stopping; private int _outstandingRequests; - private TaskCompletionSource _shutdownSignal; + private readonly TaskCompletionSource _shutdownSignal = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + private int _shutdownSignalCompleted; private readonly ServerAddressesFeature _serverAddresses; @@ -56,13 +57,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys _processRequest = new Action(ProcessRequestAsync); _maxAccepts = _options.MaxAccepts; - _shutdownSignal = new TaskCompletionSource(); } internal HttpSysListener Listener { get; } public IFeatureCollection Features { get; } + private bool Stopping => _stopping == 1; + public Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) { if (application == null) @@ -146,7 +148,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private async void ProcessRequestsWorker() { int workerIndex = Interlocked.Increment(ref _acceptorCounts); - while (!_stopping && workerIndex <= _maxAccepts) + while (!Stopping && workerIndex <= _maxAccepts) { // Receive a request RequestContext requestContext; @@ -156,8 +158,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } catch (Exception exception) { - Contract.Assert(_stopping); - if (_stopping) + Contract.Assert(Stopping); + if (Stopping) { LogHelper.LogDebug(_logger, "ListenForNextRequestAsync-Stopping", exception); } @@ -186,7 +188,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var requestContext = requestContextObj as RequestContext; try { - if (_stopping) + if (Stopping) { SetFatalResponse(requestContext, 503); return; @@ -227,7 +229,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } finally { - if (Interlocked.Decrement(ref _outstandingRequests) == 0 && _stopping) + if (Interlocked.Decrement(ref _outstandingRequests) == 0 && Stopping) { LogHelper.LogInfo(_logger, "All requests drained."); _shutdownSignal.TrySetResult(0); @@ -250,28 +252,51 @@ namespace Microsoft.AspNetCore.Server.HttpSys public Task StopAsync(CancellationToken cancellationToken) { - _stopping = true; - // Wait for active requests to drain - if (_outstandingRequests > 0) + void RegisterCancelation() { - LogHelper.LogInfo(_logger, "Stopping, waiting for " + _outstandingRequests + " request(s) to drain."); - - var waitForStop = new TaskCompletionSource(); cancellationToken.Register(() => { - LogHelper.LogInfo(_logger, "Timed out, terminating " + _outstandingRequests + " request(s)."); - waitForStop.TrySetResult(0); + if (Interlocked.Exchange(ref _shutdownSignalCompleted, 1) == 0) + { + LogHelper.LogInfo(_logger, "Canceled, terminating " + _outstandingRequests + " request(s)."); + _shutdownSignal.TrySetResult(null); + } }); - - return Task.WhenAny(_shutdownSignal.Task, waitForStop.Task); } - return Task.CompletedTask; + if (Interlocked.Exchange(ref _stopping, 1) == 1) + { + RegisterCancelation(); + + return _shutdownSignal.Task; + } + + try + { + // Wait for active requests to drain + if (_outstandingRequests > 0) + { + LogHelper.LogInfo(_logger, "Stopping, waiting for " + _outstandingRequests + " request(s) to drain."); + RegisterCancelation(); + } + else + { + _shutdownSignal.TrySetResult(null); + } + } + catch (Exception ex) + { + _shutdownSignal.TrySetException(ex); + } + + return _shutdownSignal.Task; } public void Dispose() { - _stopping = true; + _stopping = 1; + _shutdownSignal.TrySetResult(null); + Listener.Dispose(); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 9e5bc9e444..b5c9734bb7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -406,6 +407,194 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + [ConditionalFact] + public async Task Server_MultipleStopAsyncCallsWaitForRequestsToDrain_Success() + { + Task responseTask; + ManualResetEvent received = new ManualResetEvent(false); + ManualResetEvent run = new ManualResetEvent(false); + string address; + using (var server = Utilities.CreateHttpServer(out address, httpContext => + { + received.Set(); + Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); + })) + { + responseTask = SendRequestAsync(address); + Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var stopTask1 = server.StopAsync(cts.Token); + var stopTask2 = server.StopAsync(cts.Token); + var stopTask3 = server.StopAsync(cts.Token); + + Assert.False(stopTask1.IsCompleted); + Assert.False(stopTask2.IsCompleted); + Assert.False(stopTask3.IsCompleted); + + run.Set(); + + await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); + } + string response = await responseTask; + Assert.Equal("Hello World", response); + } + + [ConditionalFact] + public async Task Server_MultipleStopAsyncCallsCompleteOnCancellation_SameToken_Success() + { + Task responseTask; + ManualResetEvent received = new ManualResetEvent(false); + ManualResetEvent run = new ManualResetEvent(false); + string address; + using (var server = Utilities.CreateHttpServer(out address, httpContext => + { + received.Set(); + Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); + })) + { + responseTask = SendRequestAsync(address); + Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + + var cts = new CancellationTokenSource(); + var stopTask1 = server.StopAsync(cts.Token); + var stopTask2 = server.StopAsync(cts.Token); + var stopTask3 = server.StopAsync(cts.Token); + + Assert.False(stopTask1.IsCompleted); + Assert.False(stopTask2.IsCompleted); + Assert.False(stopTask3.IsCompleted); + + cts.Cancel(); + + await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); + + run.Set(); + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task Server_MultipleStopAsyncCallsCompleteOnSingleCancellation_FirstToken_Success() + { + Task responseTask; + ManualResetEvent received = new ManualResetEvent(false); + ManualResetEvent run = new ManualResetEvent(false); + string address; + using (var server = Utilities.CreateHttpServer(out address, httpContext => + { + received.Set(); + Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); + })) + { + responseTask = SendRequestAsync(address); + Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + + var cts = new CancellationTokenSource(); + var stopTask1 = server.StopAsync(cts.Token); + var stopTask2 = server.StopAsync(new CancellationTokenSource().Token); + var stopTask3 = server.StopAsync(new CancellationTokenSource().Token); + + Assert.False(stopTask1.IsCompleted); + Assert.False(stopTask2.IsCompleted); + Assert.False(stopTask3.IsCompleted); + + cts.Cancel(); + + await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); + + run.Set(); + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task Server_MultipleStopAsyncCallsCompleteOnSingleCancellation_SubsequentToken_Success() + { + Task responseTask; + ManualResetEvent received = new ManualResetEvent(false); + ManualResetEvent run = new ManualResetEvent(false); + string address; + using (var server = Utilities.CreateHttpServer(out address, httpContext => + { + received.Set(); + Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); + })) + { + responseTask = SendRequestAsync(address); + Assert.True(received.WaitOne(10000)); + + var cts = new CancellationTokenSource(); + var stopTask1 = server.StopAsync(new CancellationTokenSource().Token); + var stopTask2 = server.StopAsync(cts.Token); + var stopTask3 = server.StopAsync(new CancellationTokenSource().Token); + + Assert.False(stopTask1.IsCompleted); + Assert.False(stopTask2.IsCompleted); + Assert.False(stopTask3.IsCompleted); + + cts.Cancel(); + + await Task.WhenAll(stopTask1, stopTask2, stopTask3).TimeoutAfter(TimeSpan.FromSeconds(10)); + + run.Set(); + + string response = await responseTask; + Assert.Equal("Hello World", response); + } + } + + [ConditionalFact] + public async Task Server_DisposeContinuesPendingStopAsyncCalls() + { + Task responseTask; + ManualResetEvent received = new ManualResetEvent(false); + ManualResetEvent run = new ManualResetEvent(false); + string address; + Task stopTask1; + Task stopTask2; + using (var server = Utilities.CreateHttpServer(out address, httpContext => + { + received.Set(); + Assert.True(run.WaitOne(TimeSpan.FromSeconds(10))); + httpContext.Response.ContentLength = 11; + return httpContext.Response.WriteAsync("Hello World"); + })) + { + responseTask = SendRequestAsync(address); + Assert.True(received.WaitOne(TimeSpan.FromSeconds(10))); + + stopTask1 = server.StopAsync(new CancellationTokenSource().Token); + stopTask2 = server.StopAsync(new CancellationTokenSource().Token); + + Assert.False(stopTask1.IsCompleted); + Assert.False(stopTask2.IsCompleted); + } + + await Task.WhenAll(stopTask1, stopTask2).TimeoutAfter(TimeSpan.FromSeconds(10)); + } + + [ConditionalFact] + public async Task Server_StopAsyncCalledWithNoRequests_Success() + { + using (var server = Utilities.CreateHttpServer(out _, httpContext => Task.CompletedTask)) + { + await server.StopAsync(default(CancellationToken)).TimeoutAfter(TimeSpan.FromSeconds(10)); + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) From 87189875ff853835e24faa031251a1cadc4fc4ad Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Thu, 24 Aug 2017 13:43:04 -0700 Subject: [PATCH 527/597] Increase timeout in Server_ClientDisconnects_CallCanceled to mitigate test flakiness. --- .../ServerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index b5c9734bb7..22d53e02f7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -219,7 +219,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys [ConditionalFact] public async Task Server_ClientDisconnects_CallCanceled() { - TimeSpan interval = TimeSpan.FromSeconds(1); + TimeSpan interval = TimeSpan.FromSeconds(10); ManualResetEvent received = new ManualResetEvent(false); ManualResetEvent aborted = new ManualResetEvent(false); ManualResetEvent canceled = new ManualResetEvent(false); From 4595e91a7d4fed9dac5de0a24168c4b1f82ba9ec Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 29 Aug 2017 12:37:28 -0700 Subject: [PATCH 528/597] Use Directory.Build.props/targets --- appveyor.yml => .appveyor.yml | 0 build/common.props => Directory.Build.props | 13 ++++--------- Directory.Build.targets | 2 ++ HttpSysServer.sln | 16 +++++++++++++--- samples/HotAddSample/HotAddSample.csproj | 2 -- samples/SelfHostServer/SelfHostServer.csproj | 2 -- src/Directory.Build.props | 7 +++++++ .../Microsoft.AspNetCore.Server.HttpSys.csproj | 2 -- test/Directory.Build.props | 11 +++++++++++ ...NetCore.Server.HttpSys.FunctionalTests.csproj | 8 +------- ...rosoft.AspNetCore.Server.HttpSys.Tests.csproj | 5 ----- 11 files changed, 38 insertions(+), 30 deletions(-) rename appveyor.yml => .appveyor.yml (100%) rename build/common.props => Directory.Build.props (60%) create mode 100644 Directory.Build.targets create mode 100644 src/Directory.Build.props create mode 100644 test/Directory.Build.props diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml diff --git a/build/common.props b/Directory.Build.props similarity index 60% rename from build/common.props rename to Directory.Build.props index d893ee6ec6..85766bd6f5 100644 --- a/build/common.props +++ b/Directory.Build.props @@ -1,20 +1,15 @@ - - - + + + Microsoft ASP.NET Core https://github.com/aspnet/HttpSysServer git - $(MSBuildThisFileDirectory)Key.snk + $(MSBuildThisFileDirectory)build\Key.snk true true $(VersionSuffix)-$(BuildNumber) true - - - - - diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000000..f75adf7e4d --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,2 @@ + + diff --git a/HttpSysServer.sln b/HttpSysServer.sln index dcf802bb78..c6cff03ee9 100644 --- a/HttpSysServer.sln +++ b/HttpSysServer.sln @@ -1,20 +1,28 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.9 +VisualStudioVersion = 15.0.26730.10 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{99D5E5F3-88F5-4CCF-8D8C-717C8925DF09}" + ProjectSection(SolutionItems) = preProject + src\Directory.Build.props = src\Directory.Build.props + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E183C826-1360-4DFF-9994-F33CED5C8525}" + ProjectSection(SolutionItems) = preProject + test\Directory.Build.props = test\Directory.Build.props + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3A1E31E3-2794-4CA3-B8E2-253E96BDE514}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5E9B546C-17AC-4BDF-BCB3-5955D4755ED8}" ProjectSection(SolutionItems) = preProject + .appveyor.yml = .appveyor.yml .travis.yml = .travis.yml - appveyor.yml = appveyor.yml build.cmd = build.cmd build.ps1 = build.ps1 build.sh = build.sh + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets NuGet.config = NuGet.config version.xml = version.xml EndProjectSection @@ -33,7 +41,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{85914BA9-4168-48C5-9C3F-E2E8B1479A6E}" ProjectSection(SolutionItems) = preProject - build\common.props = build\common.props build\dependencies.props = build\dependencies.props build\Key.snk = build\Key.snk EndProjectSection @@ -125,4 +132,7 @@ Global {E837249E-E666-4DF2-AFC3-7A4D70234F9F} = {E183C826-1360-4DFF-9994-F33CED5C8525} {85914BA9-4168-48C5-9C3F-E2E8B1479A6E} = {5E9B546C-17AC-4BDF-BCB3-5955D4755ED8} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {34B42B42-FA09-41AB-9216-14073990C504} + EndGlobalSection EndGlobal diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index 6620ed7c5d..af5fdda499 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 Exe diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index 6620ed7c5d..af5fdda499 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 Exe diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000000..d704a37df9 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index 2e8a9ab592..c70fd31131 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -1,7 +1,5 @@  - - ASP.NET Core HTTP server that uses the Windows HTTP Server API. netstandard2.0 diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 0000000000..c30afd54ff --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index 8db416c863..ba4a84ed9b 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -1,6 +1,4 @@ - - - + netcoreapp2.0;net461 @@ -12,11 +10,7 @@ - - - - diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index f8e1c7ff0f..0429172ecd 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -1,7 +1,5 @@  - - netcoreapp2.0;net461 netcoreapp2.0 @@ -9,9 +7,6 @@ - - - From 9c78b5a8becca676157cfe94aa31812991545661 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 29 Aug 2017 12:39:24 -0700 Subject: [PATCH 529/597] Use PackageLineup to manage PackageReference versions --- Directory.Build.props | 1 - Directory.Build.targets | 14 +++++++++++++- NuGet.config | 1 - build/dependencies.props | 12 ------------ build/repo.props | 6 ++++++ samples/HotAddSample/HotAddSample.csproj | 5 ++++- samples/SelfHostServer/SelfHostServer.csproj | 5 ++++- src/Directory.Build.props | 2 +- .../Microsoft.AspNetCore.Server.HttpSys.csproj | 10 +++++----- test/Directory.Build.props | 10 +++++----- ...spNetCore.Server.HttpSys.FunctionalTests.csproj | 2 +- 11 files changed, 39 insertions(+), 29 deletions(-) delete mode 100644 build/dependencies.props create mode 100644 build/repo.props diff --git a/Directory.Build.props b/Directory.Build.props index 85766bd6f5..c0098b5168 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,4 @@  - diff --git a/Directory.Build.targets b/Directory.Build.targets index f75adf7e4d..bc118fd907 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,2 +1,14 @@ - + + + + <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh + <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd + <_BootstrapperError> + Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. + Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. + + + + + diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..20060c934e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,7 +3,6 @@ - diff --git a/build/dependencies.props b/build/dependencies.props deleted file mode 100644 index 1235e00530..0000000000 --- a/build/dependencies.props +++ /dev/null @@ -1,12 +0,0 @@ - - - 2.1.0-* - 4.4.0-* - 2.1.1-* - 2.0.0-* - 2.0.0-* - 2.0.0-* - 15.3.0 - 2.3.0-beta4-build3742 - - diff --git a/build/repo.props b/build/repo.props new file mode 100644 index 0000000000..13fe1c296a --- /dev/null +++ b/build/repo.props @@ -0,0 +1,6 @@ + + + + + + diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index af5fdda499..a44d7e2f0a 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -8,6 +8,9 @@ - + + + + diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index af5fdda499..a44d7e2f0a 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -8,6 +8,9 @@ - + + + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d704a37df9..9d9a3de33a 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,6 +2,6 @@ - + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index c70fd31131..a7373c095c 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -10,11 +10,11 @@ - - - - - + + + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index c30afd54ff..82ba457f18 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,10 +2,10 @@ - - - - - + + + + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index ba4a84ed9b..ee9812fa48 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -10,7 +10,7 @@ - + From e3c7e23cc4b1a37aed8a182f33d42826d22d3b5b Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Wed, 20 Sep 2017 15:28:26 -0700 Subject: [PATCH 530/597] Logging#543 Reorder request disposal due to logging. --- .../MessagePump.cs | 6 ++-- .../AuthenticationTests.cs | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 53330c6f1c..00a28df87c 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -204,17 +204,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys { await _application.ProcessRequestAsync(context).SupressContext(); await featureContext.OnResponseStart(); - requestContext.Dispose(); - _application.DisposeContext(context, null); } finally { await featureContext.OnCompleted(); } + _application.DisposeContext(context, null); + requestContext.Dispose(); } catch (Exception ex) { LogHelper.LogException(_logger, "ProcessRequestAsync", ex); + _application.DisposeContext(context, ex); if (requestContext.Response.HasStarted) { requestContext.Abort(); @@ -225,7 +226,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys requestContext.Response.Headers.Clear(); SetFatalResponse(requestContext, 500); } - _application.DisposeContext(context, ex); } finally { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index 87a712fa24..7a4a184087 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Testing.xunit; @@ -165,6 +166,34 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + // https://github.com/aspnet/Logging/issues/543#issuecomment-321907828 + [ConditionalFact] + public async Task AuthTypes_AccessUserInOnCompleted_Success() + { + var completed = new ManualResetEvent(false); + string userName = null; + var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM; + using (var server = Utilities.CreateDynamicHost(authTypes, DenyAnoymous, out var address, httpContext => + { + Assert.NotNull(httpContext.User); + Assert.NotNull(httpContext.User.Identity); + Assert.True(httpContext.User.Identity.IsAuthenticated); + httpContext.Response.OnCompleted(() => + { + userName = httpContext.User.Identity.Name; + completed.Set(); + return Task.FromResult(0); + }); + return Task.FromResult(0); + })) + { + var response = await SendRequestAsync(address, useDefaultCredentials: true); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(completed.WaitOne(TimeSpan.FromSeconds(5))); + Assert.False(string.IsNullOrEmpty(userName)); + } + } + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] From 58f82c5b327b8d3ac5843f05fa8cbc997b50e33c Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 21 Sep 2017 17:48:17 -0700 Subject: [PATCH 531/597] Increase Minimum Version of Visual Studio to 15.3.0 --- HttpSysServer.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HttpSysServer.sln b/HttpSysServer.sln index c6cff03ee9..9468f957f1 100644 --- a/HttpSysServer.sln +++ b/HttpSysServer.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26730.10 -MinimumVisualStudioVersion = 10.0.40219.1 +MinimumVisualStudioVersion = 15.0.26730.03 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{99D5E5F3-88F5-4CCF-8D8C-717C8925DF09}" ProjectSection(SolutionItems) = preProject src\Directory.Build.props = src\Directory.Build.props From 231cbffe1a5cc0abce11e2d0685683ed74fc7ad5 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 25 Sep 2017 15:53:33 -0700 Subject: [PATCH 532/597] Create shared package folder for IIS Integration In-process. (#397) --- HttpSysServer.sln | 38 + NuGetPackageVerifier.json | 6 + .../Constants.cs | 2 +- .../NativeInterop/CookedUrl.cs | 6 +- .../NativeInterop/HeapAllocHandle.cs | 2 +- .../NativeInterop/HttpApiTypes.cs | 694 ++++++++++++++++++ .../NativeInterop/HttpSysRequestHeader.cs | 2 +- .../NativeInterop/HttpSysResponseHeader.cs | 2 +- .../NativeInterop/NclUtilities.cs | 2 +- .../SafeLocalFreeChannelBinding.cs | 2 +- .../NativeInterop/SafeLocalMemHandle.cs | 2 +- .../NativeInterop/SafeNativeOverlapped.cs | 2 +- .../NativeInterop/SocketAddress.cs | 3 +- .../NativeInterop/UnsafeNativeMethods.cs | 2 +- .../RequestProcessing/HeaderCollection.cs | 2 +- .../RequestProcessing/HeaderEncoding.cs | 8 +- .../RequestProcessing/HeaderParser.cs | 3 +- .../RequestProcessing/HttpKnownHeaderNames.cs | 2 +- .../RequestProcessing/NativeRequestContext.cs | 455 ++++++++++++ .../RequestProcessing/RawUrlHelper.cs | 2 +- .../RequestHeaders.Generated.cs | 2 +- .../RequestProcessing/RequestHeaders.cs | 119 ++- .../RequestProcessing/RequestUriBuilder.cs | 2 +- .../RequestProcessing/SslStatus.cs | 2 +- .../AsyncAcceptContext.cs | 55 +- .../AuthenticationManager.cs | 15 +- .../HttpSysListener.cs | 35 +- .../MessagePump.cs | 1 + ...Microsoft.AspNetCore.Server.HttpSys.csproj | 4 + .../NativeInterop/AddressFamily.cs | 168 ----- .../NativeInterop/DisconnectListener.cs | 1 + .../NativeInterop/HttpApi.cs | 686 +---------------- .../NativeInterop/HttpRequestQueueV2Handle.cs | 1 + .../NativeInterop/HttpServerSessionHandle.cs | 3 +- .../NativeInterop/RequestQueue.cs | 17 +- .../NativeInterop/ServerSession.cs | 1 + .../NativeInterop/TokenBindingUtil.cs | 5 +- .../NativeInterop/UrlGroup.cs | 15 +- .../RequestProcessing/ClientCertLoader.cs | 25 +- .../RequestProcessing/NativeRequestContext.cs | 434 ----------- .../RequestProcessing/Request.cs | 22 +- .../RequestProcessing/RequestContext.cs | 1 + .../RequestProcessing/RequestStream.cs | 1 + .../RequestStreamAsyncResult.cs | 1 + .../RequestProcessing/Response.cs | 79 +- .../RequestProcessing/ResponseBody.cs | 31 +- .../ResponseStreamAsyncResult.cs | 24 +- .../TimeoutManager.cs | 43 +- .../UrlPrefix.cs | 1 + .../MessagePumpTests.cs | 1 + .../RequestTests.cs | 1 + 51 files changed, 1557 insertions(+), 1476 deletions(-) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/Constants.cs (93%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/CookedUrl.cs (89%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/HeapAllocHandle.cs (94%) create mode 100644 shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/HttpSysRequestHeader.cs (98%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/HttpSysResponseHeader.cs (97%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/NclUtilities.cs (90%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/SafeLocalFreeChannelBinding.cs (96%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/SafeLocalMemHandle.cs (93%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/SafeNativeOverlapped.cs (97%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/SocketAddress.cs (99%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/NativeInterop/UnsafeNativeMethods.cs (99%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/HeaderCollection.cs (99%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/HeaderEncoding.cs (79%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/HeaderParser.cs (96%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/HttpKnownHeaderNames.cs (98%) create mode 100644 shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/RawUrlHelper.cs (99%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/RequestHeaders.Generated.cs (99%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/RequestHeaders.cs (57%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/RequestUriBuilder.cs (99%) rename {src/Microsoft.AspNetCore.Server.HttpSys => shared/Microsoft.AspNetCore.HttpSys.Sources}/RequestProcessing/SslStatus.cs (85%) delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs delete mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs diff --git a/HttpSysServer.sln b/HttpSysServer.sln index 9468f957f1..adc3b6d351 100644 --- a/HttpSysServer.sln +++ b/HttpSysServer.sln @@ -45,6 +45,41 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{85914BA9 build\Key.snk = build\Key.snk EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{AB6964C9-A7AF-4FAC-BEA1-C8A538EC989E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.AspNetCore.HttpSys.Sources", "Microsoft.AspNetCore.HttpSys.Sources", "{4AB1E069-2A8A-4D46-98AE-CC82E3497038}" + ProjectSection(SolutionItems) = preProject + shared\Microsoft.AspNetCore.HttpSys.Sources\Constants.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\Constants.cs + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NativeInterop", "NativeInterop", "{94AD33C9-1BDD-4385-A850-4B24FD5D5012}" + ProjectSection(SolutionItems) = preProject + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\CookedUrl.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\CookedUrl.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HeapAllocHandle.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HeapAllocHandle.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpApiTypes.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpApiTypes.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpSysRequestHeader.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpSysRequestHeader.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpSysResponseHeader.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpSysResponseHeader.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\NativeRequestInput.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\NativeRequestInput.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\NclUtilities.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\NclUtilities.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeLocalFreeChannelBinding.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeLocalFreeChannelBinding.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeLocalMemHandle.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeLocalMemHandle.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeNativeOverlapped.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeNativeOverlapped.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SocketAddress.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SocketAddress.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\UnsafeNativeMethods.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\UnsafeNativeMethods.cs + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RequestProcessing", "RequestProcessing", "{AA8C91BD-D558-468B-9258-1E186884F78D}" + ProjectSection(SolutionItems) = preProject + shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderCollection.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderCollection.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderEncoding.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderEncoding.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderParser.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderParser.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HttpKnownHeaderNames.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HttpKnownHeaderNames.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\NativeRequestContext.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\NativeRequestContext.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\RequestHeaders.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\RequestHeaders.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\RequestHeaders.Generated.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\RequestHeaders.Generated.cs + shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\SslStatus.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\SslStatus.cs + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -131,6 +166,9 @@ Global {8BFA392A-8B67-4454-916B-67C545EDFAEF} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514} {E837249E-E666-4DF2-AFC3-7A4D70234F9F} = {E183C826-1360-4DFF-9994-F33CED5C8525} {85914BA9-4168-48C5-9C3F-E2E8B1479A6E} = {5E9B546C-17AC-4BDF-BCB3-5955D4755ED8} + {4AB1E069-2A8A-4D46-98AE-CC82E3497038} = {AB6964C9-A7AF-4FAC-BEA1-C8A538EC989E} + {94AD33C9-1BDD-4385-A850-4B24FD5D5012} = {4AB1E069-2A8A-4D46-98AE-CC82E3497038} + {AA8C91BD-D558-468B-9258-1E186884F78D} = {4AB1E069-2A8A-4D46-98AE-CC82E3497038} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {34B42B42-FA09-41AB-9216-14073990C504} diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index b153ab1515..c02b36b40a 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,4 +1,10 @@ { + "adx-nonshipping": { + "rules": [], + "packages": { + "Microsoft.AspNetCore.HttpSys.Sources": {} + } + }, "Default": { "rules": [ "DefaultCompositeRule" diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs similarity index 93% rename from src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs index d7b5382d18..0982badab8 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class Constants { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs similarity index 89% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs index a444c48854..ee5b2ec53d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs @@ -4,14 +4,14 @@ using System; using System.Runtime.InteropServices; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { // Note this type should only be used while the request buffer remains pinned internal class CookedUrl { - private readonly HttpApi.HTTP_COOKED_URL _nativeCookedUrl; + private readonly HttpApiTypes.HTTP_COOKED_URL _nativeCookedUrl; - internal CookedUrl(HttpApi.HTTP_COOKED_URL nativeCookedUrl) + internal CookedUrl(HttpApiTypes.HTTP_COOKED_URL nativeCookedUrl) { _nativeCookedUrl = nativeCookedUrl; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs similarity index 94% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs index 289252e7dc..9175fd8572 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs @@ -4,7 +4,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal sealed class HeapAllocHandle : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs new file mode 100644 index 0000000000..6b3a3b6908 --- /dev/null +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs @@ -0,0 +1,694 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +namespace Microsoft.AspNetCore.HttpSys.Internal +{ + internal static unsafe class HttpApiTypes + { + internal enum HTTP_API_VERSION + { + Invalid, + Version10, + Version20, + } + + // see http.w for definitions + internal enum HTTP_SERVER_PROPERTY + { + HttpServerAuthenticationProperty, + HttpServerLoggingProperty, + HttpServerQosProperty, + HttpServerTimeoutsProperty, + HttpServerQueueLengthProperty, + HttpServerStateProperty, + HttpServer503VerbosityProperty, + HttpServerBindingProperty, + HttpServerExtendedAuthenticationProperty, + HttpServerListenEndpointProperty, + HttpServerChannelBindProperty, + HttpServerProtectionLevelProperty, + } + + // Currently only one request info type is supported but the enum is for future extensibility. + + internal enum HTTP_REQUEST_INFO_TYPE + { + HttpRequestInfoTypeAuth, + HttpRequestInfoTypeChannelBind, + HttpRequestInfoTypeSslProtocol, + HttpRequestInfoTypeSslTokenBinding + } + + internal enum HTTP_RESPONSE_INFO_TYPE + { + HttpResponseInfoTypeMultipleKnownHeaders, + HttpResponseInfoTypeAuthenticationProperty, + HttpResponseInfoTypeQosProperty, + } + + internal enum HTTP_TIMEOUT_TYPE + { + EntityBody, + DrainEntityBody, + RequestQueue, + IdleConnection, + HeaderWait, + MinSendRate, + } + + internal const int MaxTimeout = 6; + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_VERSION + { + internal ushort MajorVersion; + internal ushort MinorVersion; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_KNOWN_HEADER + { + internal ushort RawValueLength; + internal byte* pRawValue; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct HTTP_DATA_CHUNK + { + [FieldOffset(0)] + internal HTTP_DATA_CHUNK_TYPE DataChunkType; + + [FieldOffset(8)] + internal FromMemory fromMemory; + + [FieldOffset(8)] + internal FromFileHandle fromFile; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct FromMemory + { + // 4 bytes for 32bit, 8 bytes for 64bit + internal IntPtr pBuffer; + internal uint BufferLength; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct FromFileHandle + { + internal ulong offset; + internal ulong count; + internal IntPtr fileHandle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTPAPI_VERSION + { + internal ushort HttpApiMajorVersion; + internal ushort HttpApiMinorVersion; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_COOKED_URL + { + internal ushort FullUrlLength; + internal ushort HostLength; + internal ushort AbsPathLength; + internal ushort QueryStringLength; + internal ushort* pFullUrl; + internal ushort* pHost; + internal ushort* pAbsPath; + internal ushort* pQueryString; + } + + // Only cache unauthorized GETs + HEADs. + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_CACHE_POLICY + { + internal HTTP_CACHE_POLICY_TYPE Policy; + internal uint SecondsToLive; + } + + internal enum HTTP_CACHE_POLICY_TYPE : int + { + HttpCachePolicyNocache = 0, + HttpCachePolicyUserInvalidates = 1, + HttpCachePolicyTimeToLive = 2, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SOCKADDR + { + internal ushort sa_family; + internal byte sa_data; + internal byte sa_data_02; + internal byte sa_data_03; + internal byte sa_data_04; + internal byte sa_data_05; + internal byte sa_data_06; + internal byte sa_data_07; + internal byte sa_data_08; + internal byte sa_data_09; + internal byte sa_data_10; + internal byte sa_data_11; + internal byte sa_data_12; + internal byte sa_data_13; + internal byte sa_data_14; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_TRANSPORT_ADDRESS + { + internal SOCKADDR* pRemoteAddress; + internal SOCKADDR* pLocalAddress; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SSL_CLIENT_CERT_INFO + { + internal uint CertFlags; + internal uint CertEncodedSize; + internal byte* pCertEncoded; + internal void* Token; + internal byte CertDeniedByMapper; + } + + internal enum HTTP_SERVICE_BINDING_TYPE : uint + { + HttpServiceBindingTypeNone = 0, + HttpServiceBindingTypeW, + HttpServiceBindingTypeA + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVICE_BINDING_BASE + { + internal HTTP_SERVICE_BINDING_TYPE Type; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_CHANNEL_BIND_STATUS + { + internal IntPtr ServiceName; + internal IntPtr ChannelToken; + internal uint ChannelTokenSize; + internal uint Flags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_UNKNOWN_HEADER + { + internal ushort NameLength; + internal ushort RawValueLength; + internal byte* pName; + internal byte* pRawValue; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SSL_INFO + { + internal ushort ServerCertKeySize; + internal ushort ConnectionKeySize; + internal uint ServerCertIssuerSize; + internal uint ServerCertSubjectSize; + internal byte* pServerCertIssuer; + internal byte* pServerCertSubject; + internal HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo; + internal uint SslClientCertNegotiated; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_HEADERS + { + internal ushort UnknownHeaderCount; + internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; + internal ushort TrailerCount; + internal HTTP_UNKNOWN_HEADER* pTrailers; + internal HTTP_KNOWN_HEADER KnownHeaders; + internal HTTP_KNOWN_HEADER KnownHeaders_02; + internal HTTP_KNOWN_HEADER KnownHeaders_03; + internal HTTP_KNOWN_HEADER KnownHeaders_04; + internal HTTP_KNOWN_HEADER KnownHeaders_05; + internal HTTP_KNOWN_HEADER KnownHeaders_06; + internal HTTP_KNOWN_HEADER KnownHeaders_07; + internal HTTP_KNOWN_HEADER KnownHeaders_08; + internal HTTP_KNOWN_HEADER KnownHeaders_09; + internal HTTP_KNOWN_HEADER KnownHeaders_10; + internal HTTP_KNOWN_HEADER KnownHeaders_11; + internal HTTP_KNOWN_HEADER KnownHeaders_12; + internal HTTP_KNOWN_HEADER KnownHeaders_13; + internal HTTP_KNOWN_HEADER KnownHeaders_14; + internal HTTP_KNOWN_HEADER KnownHeaders_15; + internal HTTP_KNOWN_HEADER KnownHeaders_16; + internal HTTP_KNOWN_HEADER KnownHeaders_17; + internal HTTP_KNOWN_HEADER KnownHeaders_18; + internal HTTP_KNOWN_HEADER KnownHeaders_19; + internal HTTP_KNOWN_HEADER KnownHeaders_20; + internal HTTP_KNOWN_HEADER KnownHeaders_21; + internal HTTP_KNOWN_HEADER KnownHeaders_22; + internal HTTP_KNOWN_HEADER KnownHeaders_23; + internal HTTP_KNOWN_HEADER KnownHeaders_24; + internal HTTP_KNOWN_HEADER KnownHeaders_25; + internal HTTP_KNOWN_HEADER KnownHeaders_26; + internal HTTP_KNOWN_HEADER KnownHeaders_27; + internal HTTP_KNOWN_HEADER KnownHeaders_28; + internal HTTP_KNOWN_HEADER KnownHeaders_29; + internal HTTP_KNOWN_HEADER KnownHeaders_30; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_HEADERS + { + internal ushort UnknownHeaderCount; + internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; + internal ushort TrailerCount; + internal HTTP_UNKNOWN_HEADER* pTrailers; + internal HTTP_KNOWN_HEADER KnownHeaders; + internal HTTP_KNOWN_HEADER KnownHeaders_02; + internal HTTP_KNOWN_HEADER KnownHeaders_03; + internal HTTP_KNOWN_HEADER KnownHeaders_04; + internal HTTP_KNOWN_HEADER KnownHeaders_05; + internal HTTP_KNOWN_HEADER KnownHeaders_06; + internal HTTP_KNOWN_HEADER KnownHeaders_07; + internal HTTP_KNOWN_HEADER KnownHeaders_08; + internal HTTP_KNOWN_HEADER KnownHeaders_09; + internal HTTP_KNOWN_HEADER KnownHeaders_10; + internal HTTP_KNOWN_HEADER KnownHeaders_11; + internal HTTP_KNOWN_HEADER KnownHeaders_12; + internal HTTP_KNOWN_HEADER KnownHeaders_13; + internal HTTP_KNOWN_HEADER KnownHeaders_14; + internal HTTP_KNOWN_HEADER KnownHeaders_15; + internal HTTP_KNOWN_HEADER KnownHeaders_16; + internal HTTP_KNOWN_HEADER KnownHeaders_17; + internal HTTP_KNOWN_HEADER KnownHeaders_18; + internal HTTP_KNOWN_HEADER KnownHeaders_19; + internal HTTP_KNOWN_HEADER KnownHeaders_20; + internal HTTP_KNOWN_HEADER KnownHeaders_21; + internal HTTP_KNOWN_HEADER KnownHeaders_22; + internal HTTP_KNOWN_HEADER KnownHeaders_23; + internal HTTP_KNOWN_HEADER KnownHeaders_24; + internal HTTP_KNOWN_HEADER KnownHeaders_25; + internal HTTP_KNOWN_HEADER KnownHeaders_26; + internal HTTP_KNOWN_HEADER KnownHeaders_27; + internal HTTP_KNOWN_HEADER KnownHeaders_28; + internal HTTP_KNOWN_HEADER KnownHeaders_29; + internal HTTP_KNOWN_HEADER KnownHeaders_30; + internal HTTP_KNOWN_HEADER KnownHeaders_31; + internal HTTP_KNOWN_HEADER KnownHeaders_32; + internal HTTP_KNOWN_HEADER KnownHeaders_33; + internal HTTP_KNOWN_HEADER KnownHeaders_34; + internal HTTP_KNOWN_HEADER KnownHeaders_35; + internal HTTP_KNOWN_HEADER KnownHeaders_36; + internal HTTP_KNOWN_HEADER KnownHeaders_37; + internal HTTP_KNOWN_HEADER KnownHeaders_38; + internal HTTP_KNOWN_HEADER KnownHeaders_39; + internal HTTP_KNOWN_HEADER KnownHeaders_40; + internal HTTP_KNOWN_HEADER KnownHeaders_41; + } + + internal enum HTTP_VERB : int + { + HttpVerbUnparsed = 0, + HttpVerbUnknown = 1, + HttpVerbInvalid = 2, + HttpVerbOPTIONS = 3, + HttpVerbGET = 4, + HttpVerbHEAD = 5, + HttpVerbPOST = 6, + HttpVerbPUT = 7, + HttpVerbDELETE = 8, + HttpVerbTRACE = 9, + HttpVerbCONNECT = 10, + HttpVerbTRACK = 11, + HttpVerbMOVE = 12, + HttpVerbCOPY = 13, + HttpVerbPROPFIND = 14, + HttpVerbPROPPATCH = 15, + HttpVerbMKCOL = 16, + HttpVerbLOCK = 17, + HttpVerbUNLOCK = 18, + HttpVerbSEARCH = 19, + HttpVerbMaximum = 20, + } + + internal static readonly string[] HttpVerbs = new string[] + { + null, + "Unknown", + "Invalid", + "OPTIONS", + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "TRACE", + "CONNECT", + "TRACK", + "MOVE", + "COPY", + "PROPFIND", + "PROPPATCH", + "MKCOL", + "LOCK", + "UNLOCK", + "SEARCH", + }; + + internal enum HTTP_DATA_CHUNK_TYPE : int + { + HttpDataChunkFromMemory = 0, + HttpDataChunkFromFileHandle = 1, + HttpDataChunkFromFragmentCache = 2, + HttpDataChunkMaximum = 3, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_INFO + { + internal HTTP_RESPONSE_INFO_TYPE Type; + internal uint Length; + internal HTTP_MULTIPLE_KNOWN_HEADERS* pInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE + { + internal uint Flags; + internal HTTP_VERSION Version; + internal ushort StatusCode; + internal ushort ReasonLength; + internal byte* pReason; + internal HTTP_RESPONSE_HEADERS Headers; + internal ushort EntityChunkCount; + internal HTTP_DATA_CHUNK* pEntityChunks; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_RESPONSE_V2 + { + internal HTTP_RESPONSE Response_V1; + internal ushort ResponseInfoCount; + internal HTTP_RESPONSE_INFO* pResponseInfo; + } + + internal enum HTTP_RESPONSE_INFO_FLAGS : uint + { + None = 0, + PreserveOrder = 1, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_MULTIPLE_KNOWN_HEADERS + { + internal HTTP_RESPONSE_HEADER_ID.Enum HeaderId; + internal HTTP_RESPONSE_INFO_FLAGS Flags; + internal ushort KnownHeaderCount; + internal HTTP_KNOWN_HEADER* KnownHeaders; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_AUTH_INFO + { + internal HTTP_AUTH_STATUS AuthStatus; + internal uint SecStatus; + internal uint Flags; + internal HTTP_REQUEST_AUTH_TYPE AuthType; + internal IntPtr AccessToken; + internal uint ContextAttributes; + internal uint PackedContextLength; + internal uint PackedContextType; + internal IntPtr PackedContext; + internal uint MutualAuthDataLength; + internal char* pMutualAuthData; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_INFO + { + internal HTTP_REQUEST_INFO_TYPE InfoType; + internal uint InfoLength; + internal HTTP_REQUEST_AUTH_INFO* pInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST + { + internal uint Flags; + internal ulong ConnectionId; + internal ulong RequestId; + internal ulong UrlContext; + internal HTTP_VERSION Version; + internal HTTP_VERB Verb; + internal ushort UnknownVerbLength; + internal ushort RawUrlLength; + internal byte* pUnknownVerb; + internal byte* pRawUrl; + internal HTTP_COOKED_URL CookedUrl; + internal HTTP_TRANSPORT_ADDRESS Address; + internal HTTP_REQUEST_HEADERS Headers; + internal ulong BytesReceived; + internal ushort EntityChunkCount; + internal HTTP_DATA_CHUNK* pEntityChunks; + internal ulong RawConnectionId; + internal HTTP_SSL_INFO* pSslInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_V2 + { + internal HTTP_REQUEST Request; + internal ushort RequestInfoCount; + internal HTTP_REQUEST_INFO* pRequestInfo; + } + + internal enum HTTP_AUTH_STATUS + { + HttpAuthStatusSuccess, + HttpAuthStatusNotAuthenticated, + HttpAuthStatusFailure, + } + + internal enum HTTP_REQUEST_AUTH_TYPE + { + HttpRequestAuthTypeNone = 0, + HttpRequestAuthTypeBasic, + HttpRequestAuthTypeDigest, + HttpRequestAuthTypeNTLM, + HttpRequestAuthTypeNegotiate, + HttpRequestAuthTypeKerberos + } + + internal enum HTTP_QOS_SETTING_TYPE + { + HttpQosSettingTypeBandwidth, + HttpQosSettingTypeConnectionLimit, + HttpQosSettingTypeFlowRate + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_INFO + { + internal HTTP_FLAGS Flags; + internal HTTP_AUTH_TYPES AuthSchemes; + internal bool ReceiveMutualAuth; + internal bool ReceiveContextHandle; + internal bool DisableNTLMCredentialCaching; + internal ulong ExFlags; + HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS DigestParams; + HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS BasicParams; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS + { + internal ushort DomainNameLength; + internal char* DomainName; + internal ushort RealmLength; + internal char* Realm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS + { + ushort RealmLength; + char* Realm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_REQUEST_TOKEN_BINDING_INFO + { + public byte* TokenBinding; + public uint TokenBindingSize; + + public byte* TlsUnique; + public uint TlsUniqueSize; + + public char* KeyType; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_TIMEOUT_LIMIT_INFO + { + internal HTTP_FLAGS Flags; + internal ushort EntityBody; + internal ushort DrainEntityBody; + internal ushort RequestQueue; + internal ushort IdleConnection; + internal ushort HeaderWait; + internal uint MinSendRate; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_BINDING_INFO + { + internal HTTP_FLAGS Flags; + internal IntPtr RequestQueueHandle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_CONNECTION_LIMIT_INFO + { + internal HTTP_FLAGS Flags; + internal uint MaxConnections; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HTTP_QOS_SETTING_INFO + { + internal HTTP_QOS_SETTING_TYPE QosType; + internal IntPtr QosSetting; + } + + // see http.w for definitions + [Flags] + internal enum HTTP_FLAGS : uint + { + NONE = 0x00000000, + HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY = 0x00000001, + HTTP_RECEIVE_SECURE_CHANNEL_TOKEN = 0x00000001, + HTTP_SEND_RESPONSE_FLAG_DISCONNECT = 0x00000001, + HTTP_SEND_RESPONSE_FLAG_MORE_DATA = 0x00000002, + HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA = 0x00000004, + HTTP_SEND_RESPONSE_FLAG_RAW_HEADER = 0x00000004, + HTTP_SEND_REQUEST_FLAG_MORE_DATA = 0x00000001, + HTTP_PROPERTY_FLAG_PRESENT = 0x00000001, + HTTP_INITIALIZE_SERVER = 0x00000001, + HTTP_INITIALIZE_CBT = 0x00000004, + HTTP_SEND_RESPONSE_FLAG_OPAQUE = 0x00000040, + } + + [Flags] + internal enum HTTP_AUTH_TYPES : uint + { + NONE = 0x00000000, + HTTP_AUTH_ENABLE_BASIC = 0x00000001, + HTTP_AUTH_ENABLE_DIGEST = 0x00000002, + HTTP_AUTH_ENABLE_NTLM = 0x00000004, + HTTP_AUTH_ENABLE_NEGOTIATE = 0x00000008, + HTTP_AUTH_ENABLE_KERBEROS = 0x00000010, + } + + internal static class HTTP_RESPONSE_HEADER_ID + { + private static string[] _strings = + { + "Cache-Control", + "Connection", + "Date", + "Keep-Alive", + "Pragma", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Via", + "Warning", + + "Allow", + "Content-Length", + "Content-Type", + "Content-Encoding", + "Content-Language", + "Content-Location", + "Content-MD5", + "Content-Range", + "Expires", + "Last-Modified", + + "Accept-Ranges", + "Age", + "ETag", + "Location", + "Proxy-Authenticate", + "Retry-After", + "Server", + "Set-Cookie", + "Vary", + "WWW-Authenticate", + }; + + private static Dictionary _lookupTable = CreateLookupTable(); + + private static Dictionary CreateLookupTable() + { + Dictionary lookupTable = new Dictionary((int)Enum.HttpHeaderResponseMaximum, StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++) + { + lookupTable.Add(_strings[i], i); + } + return lookupTable; + } + + internal static int IndexOfKnownHeader(string HeaderName) + { + int index; + return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1; + } + + internal enum Enum + { + HttpHeaderCacheControl = 0, // general-header [section 4.5] + HttpHeaderConnection = 1, // general-header [section 4.5] + HttpHeaderDate = 2, // general-header [section 4.5] + HttpHeaderKeepAlive = 3, // general-header [not in rfc] + HttpHeaderPragma = 4, // general-header [section 4.5] + HttpHeaderTrailer = 5, // general-header [section 4.5] + HttpHeaderTransferEncoding = 6, // general-header [section 4.5] + HttpHeaderUpgrade = 7, // general-header [section 4.5] + HttpHeaderVia = 8, // general-header [section 4.5] + HttpHeaderWarning = 9, // general-header [section 4.5] + + HttpHeaderAllow = 10, // entity-header [section 7.1] + HttpHeaderContentLength = 11, // entity-header [section 7.1] + HttpHeaderContentType = 12, // entity-header [section 7.1] + HttpHeaderContentEncoding = 13, // entity-header [section 7.1] + HttpHeaderContentLanguage = 14, // entity-header [section 7.1] + HttpHeaderContentLocation = 15, // entity-header [section 7.1] + HttpHeaderContentMd5 = 16, // entity-header [section 7.1] + HttpHeaderContentRange = 17, // entity-header [section 7.1] + HttpHeaderExpires = 18, // entity-header [section 7.1] + HttpHeaderLastModified = 19, // entity-header [section 7.1] + + // Response Headers + + HttpHeaderAcceptRanges = 20, // response-header [section 6.2] + HttpHeaderAge = 21, // response-header [section 6.2] + HttpHeaderEtag = 22, // response-header [section 6.2] + HttpHeaderLocation = 23, // response-header [section 6.2] + HttpHeaderProxyAuthenticate = 24, // response-header [section 6.2] + HttpHeaderRetryAfter = 25, // response-header [section 6.2] + HttpHeaderServer = 26, // response-header [section 6.2] + HttpHeaderSetCookie = 27, // response-header [not in rfc] + HttpHeaderVary = 28, // response-header [section 6.2] + HttpHeaderWwwAuthenticate = 29, // response-header [section 6.2] + + HttpHeaderResponseMaximum = 30, + + HttpHeaderMaximum = 41 + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs similarity index 98% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs index bf8cda9c6f..c52444b1be 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal enum HttpSysRequestHeader { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs similarity index 97% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs index 2d6ee2a915..5b00f35d29 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal enum HttpSysResponseHeader { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs similarity index 90% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs index abd74045e5..504e82a300 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class NclUtilities { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs similarity index 96% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs index eb3ecf7487..4c83257e5d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -4,7 +4,7 @@ using System; using System.Security.Authentication.ExtendedProtection; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal class SafeLocalFreeChannelBinding : ChannelBinding { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs similarity index 93% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs index 5e60f6e2d1..75fb508714 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs @@ -4,7 +4,7 @@ using System; using Microsoft.Win32.SafeHandles; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs similarity index 97% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs index 8073499996..01ba3c32f2 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.InteropServices; using System.Threading; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal class SafeNativeOverlapped : SafeHandle { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs index a06adf2913..fbe82fa7bc 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs @@ -6,9 +6,10 @@ using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; using System.Net; +using System.Net.Sockets; using System.Text; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { // a little perf app measured these times when comparing the internal // buffer implemented as a managed byte[] or unmanaged memory IntPtr diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs index 81662ac8c1..4483cbc306 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs @@ -5,7 +5,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static unsafe class UnsafeNclNativeMethods { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs index d0d6716486..504c434667 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs @@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal class HeaderCollection : IHeaderDictionary { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs similarity index 79% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs index 9c22ce1695..991571904b 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs @@ -3,7 +3,7 @@ using System.Text; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class HeaderEncoding { @@ -12,15 +12,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys // (e.g. IE and HttpWebRequest on intranets). private static Encoding Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false); - internal static unsafe string GetString(sbyte* pBytes, int byteCount) + internal static unsafe string GetString(byte* pBytes, int byteCount) { // net451: return new string(pBytes, 0, byteCount, Encoding); - var charCount = Encoding.GetCharCount((byte*)pBytes, byteCount); + var charCount = Encoding.GetCharCount(pBytes, byteCount); var chars = new char[charCount]; fixed (char* pChars = chars) { - var count = Encoding.GetChars((byte*)pBytes, byteCount, pChars, charCount); + var count = Encoding.GetChars(pBytes, byteCount, pChars, charCount); System.Diagnostics.Debug.Assert(count == charCount); } return new string(chars); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs similarity index 96% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs index 8b57bb3a4c..770a3ee3a7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs @@ -1,11 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Collections.Generic; using Microsoft.Extensions.Primitives; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class HeaderParser { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs similarity index 98% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs index 45ed640625..ac299f9785 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class HttpKnownHeaderNames { diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs new file mode 100644 index 0000000000..45d002e5b8 --- /dev/null +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs @@ -0,0 +1,455 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Security.Principal; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.HttpSys.Internal +{ + internal unsafe class NativeRequestContext : IDisposable + { + private const int AlignmentPadding = 8; + private IntPtr _originalBufferAddress; + private HttpApiTypes.HTTP_REQUEST* _nativeRequest; + private byte[] _backingBuffer; + private int _bufferAlignment; + private SafeNativeOverlapped _nativeOverlapped; + private bool _permanentlyPinned; + + // To be used by HttpSys + internal NativeRequestContext(SafeNativeOverlapped nativeOverlapped, + int bufferAlignment, + HttpApiTypes.HTTP_REQUEST* nativeRequest, + byte[] backingBuffer, + ulong requestId) + { + _nativeOverlapped = nativeOverlapped; + _bufferAlignment = bufferAlignment; + _nativeRequest = nativeRequest; + _backingBuffer = backingBuffer; + RequestId = requestId; + } + + // To be used by IIS Integration. + internal NativeRequestContext(HttpApiTypes.HTTP_REQUEST* request) + { + _nativeRequest = request; + _bufferAlignment = 0; + _permanentlyPinned = true; + } + + + internal SafeNativeOverlapped NativeOverlapped => _nativeOverlapped; + + internal HttpApiTypes.HTTP_REQUEST* NativeRequest + { + get + { + Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins()."); + return _nativeRequest; + } + } + + internal HttpApiTypes.HTTP_REQUEST_V2* NativeRequestV2 + { + get + { + Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins()."); + return (HttpApiTypes.HTTP_REQUEST_V2*)_nativeRequest; + } + } + + internal ulong RequestId + { + get { return NativeRequest->RequestId; } + set { NativeRequest->RequestId = value; } + } + + internal ulong ConnectionId => NativeRequest->ConnectionId; + + internal HttpApiTypes.HTTP_VERB VerbId => NativeRequest->Verb; + + internal ulong UrlContext => NativeRequest->UrlContext; + + internal ushort UnknownHeaderCount => NativeRequest->Headers.UnknownHeaderCount; + + internal SslStatus SslStatus + { + get + { + return NativeRequest->pSslInfo == null ? SslStatus.Insecure : + NativeRequest->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : + SslStatus.ClientCert; + } + } + + internal uint Size + { + get { return (uint)_backingBuffer.Length - AlignmentPadding; } + } + + // ReleasePins() should be called exactly once. It must be called before Dispose() is called, which means it must be called + // before an object (Request) which closes the RequestContext on demand is returned to the application. + internal void ReleasePins() + { + Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice."); + _originalBufferAddress = (IntPtr)_nativeRequest; + _nativeRequest = null; + _nativeOverlapped?.Dispose(); + _nativeOverlapped = null; + } + + public virtual void Dispose() + { + Debug.Assert(_nativeRequest == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins()."); + _nativeOverlapped?.Dispose(); + } + + // These methods require the HTTP_REQUEST to still be pinned in its original location. + + internal string GetVerb() + { + var verb = NativeRequest->Verb; + if (verb > HttpApiTypes.HTTP_VERB.HttpVerbUnknown && verb < HttpApiTypes.HTTP_VERB.HttpVerbMaximum) + { + return HttpApiTypes.HttpVerbs[(int)verb]; + } + else if (verb == HttpApiTypes.HTTP_VERB.HttpVerbUnknown && NativeRequest->pUnknownVerb != null) + { + return HeaderEncoding.GetString(NativeRequest->pUnknownVerb, NativeRequest->UnknownVerbLength); + } + + return null; + } + + internal string GetRawUrl() + { + if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0) + { + return Marshal.PtrToStringAnsi((IntPtr)NativeRequest->pRawUrl, NativeRequest->RawUrlLength); + } + return null; + } + + internal byte[] GetRawUrlInBytes() + { + if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0) + { + var result = new byte[NativeRequest->RawUrlLength]; + Marshal.Copy((IntPtr)NativeRequest->pRawUrl, result, 0, NativeRequest->RawUrlLength); + + return result; + } + + return null; + } + + internal CookedUrl GetCookedUrl() + { + return new CookedUrl(NativeRequest->CookedUrl); + } + + internal Version GetVersion() + { + var major = NativeRequest->Version.MajorVersion; + var minor = NativeRequest->Version.MinorVersion; + if (major == 1 && minor == 1) + { + return Constants.V1_1; + } + else if (major == 1 && minor == 0) + { + return Constants.V1_0; + } + return new Version(major, minor); + } + + internal bool CheckAuthenticated() + { + var requestInfo = NativeRequestV2->pRequestInfo; + var infoCount = NativeRequestV2->RequestInfoCount; + + for (int i = 0; i < infoCount; i++) + { + var info = &requestInfo[i]; + if (info != null + && info->InfoType == HttpApiTypes.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && info->pInfo->AuthStatus == HttpApiTypes.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + { + return true; + } + } + return false; + } + + internal WindowsPrincipal GetUser() + { + var requestInfo = NativeRequestV2->pRequestInfo; + var infoCount = NativeRequestV2->RequestInfoCount; + + for (int i = 0; i < infoCount; i++) + { + var info = &requestInfo[i]; + if (info != null + && info->InfoType == HttpApiTypes.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth + && info->pInfo->AuthStatus == HttpApiTypes.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) + { + // Duplicates AccessToken + var identity = new WindowsIdentity(info->pInfo->AccessToken, GetAuthTypeFromRequest(info->pInfo->AuthType)); + + // Close the original + UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(info->pInfo->AccessToken); + + return new WindowsPrincipal(identity); + } + } + + return new WindowsPrincipal(WindowsIdentity.GetAnonymous()); // Anonymous / !IsAuthenticated + } + + private static string GetAuthTypeFromRequest(HttpApiTypes.HTTP_REQUEST_AUTH_TYPE input) + { + switch (input) + { + case HttpApiTypes.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic: + return "Basic"; + case HttpApiTypes.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM: + return "NTLM"; + // case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest: + // return "Digest"; + case HttpApiTypes.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate: + return "Negotiate"; + case HttpApiTypes.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos: + return "Kerberos"; + default: + throw new NotImplementedException(input.ToString()); + } + } + + // These methods are for accessing the request structure after it has been unpinned. They need to adjust addresses + // in case GC has moved the original object. + + internal string GetKnownHeader(HttpSysRequestHeader header) + { + if (_permanentlyPinned) + { + return GetKnowHeaderHelper(header, 0, _nativeRequest); + } + else + { + fixed (byte* pMemoryBlob = _backingBuffer) + { + var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); + long fixup = pMemoryBlob - (byte*)_originalBufferAddress; + return GetKnowHeaderHelper(header, fixup, request); + } + } + } + + private string GetKnowHeaderHelper(HttpSysRequestHeader header, long fixup, HttpApiTypes.HTTP_REQUEST* request) + { + int headerIndex = (int)header; + string value = null; + + HttpApiTypes.HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; + // For known headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will point to empty string ("\0") + if (pKnownHeader->pRawValue != null) + { + value = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength); + } + + return value; + } + + internal void GetUnknownHeaders(IDictionary unknownHeaders) + { + if (_permanentlyPinned) + { + GetUnknownHeadersHelper(unknownHeaders, 0, _nativeRequest); + } + else + { + // Return value. + fixed (byte* pMemoryBlob = _backingBuffer) + { + var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); + long fixup = pMemoryBlob - (byte*)_originalBufferAddress; + GetUnknownHeadersHelper(unknownHeaders, fixup, request); + } + } + } + + private void GetUnknownHeadersHelper(IDictionary unknownHeaders, long fixup, HttpApiTypes.HTTP_REQUEST* request) + { + int index; + + // unknown headers + if (request->Headers.UnknownHeaderCount != 0) + { + var pUnknownHeader = (HttpApiTypes.HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders); + for (index = 0; index < request->Headers.UnknownHeaderCount; index++) + { + // For unknown headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will be null. + if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) + { + var headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength); + string headerValue; + if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) + { + headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength); + } + else + { + headerValue = string.Empty; + } + // Note that Http.Sys currently collapses all headers of the same name to a single coma separated string, + // so we can just call Set. + unknownHeaders[headerName] = headerValue; + } + pUnknownHeader++; + } + } + } + + internal SocketAddress GetRemoteEndPoint() + { + return GetEndPoint(localEndpoint: false); + } + + internal SocketAddress GetLocalEndPoint() + { + return GetEndPoint(localEndpoint: true); + } + + private SocketAddress GetEndPoint(bool localEndpoint) + { + if (_permanentlyPinned) + { + return GetEndPointHelper(localEndpoint, _nativeRequest, (byte *)0); + } + else + { + fixed (byte* pMemoryBlob = _backingBuffer) + { + var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); + return GetEndPointHelper(localEndpoint, request, pMemoryBlob); + } + } + } + + private SocketAddress GetEndPointHelper(bool localEndpoint, HttpApiTypes.HTTP_REQUEST* request, byte* pMemoryBlob) + { + var source = localEndpoint ? (byte*)request->Address.pLocalAddress : (byte*)request->Address.pRemoteAddress; + + if (source == null) + { + return null; + } + var address = (IntPtr)(pMemoryBlob + _bufferAlignment - (byte*)_originalBufferAddress + source); + return CopyOutAddress(address); + } + + private static SocketAddress CopyOutAddress(IntPtr address) + { + ushort addressFamily = *((ushort*)address); + if (addressFamily == (ushort)AddressFamily.InterNetwork) + { + var v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize); + fixed (byte* pBuffer = v4address.Buffer) + { + for (int index = 2; index < SocketAddress.IPv4AddressSize; index++) + { + pBuffer[index] = ((byte*)address)[index]; + } + } + return v4address; + } + if (addressFamily == (ushort)AddressFamily.InterNetworkV6) + { + var v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize); + fixed (byte* pBuffer = v6address.Buffer) + { + for (int index = 2; index < SocketAddress.IPv6AddressSize; index++) + { + pBuffer[index] = ((byte*)address)[index]; + } + } + return v6address; + } + + return null; + } + + internal uint GetChunks(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) + { + // Return value. + if (_permanentlyPinned) + { + return GetChunksHelper(ref dataChunkIndex, ref dataChunkOffset, buffer, offset, size, 0, _nativeRequest); + } + else + { + fixed (byte* pMemoryBlob = _backingBuffer) + { + var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); + long fixup = pMemoryBlob - (byte*)_originalBufferAddress; + return GetChunksHelper(ref dataChunkIndex, ref dataChunkOffset, buffer, offset, size, fixup, request); + } + } + } + + private uint GetChunksHelper(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size, long fixup, HttpApiTypes.HTTP_REQUEST* request) + { + uint dataRead = 0; + + if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) + { + var pDataChunk = (HttpApiTypes.HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); + + fixed (byte* pReadBuffer = buffer) + { + byte* pTo = &pReadBuffer[offset]; + + while (dataChunkIndex < request->EntityChunkCount && dataRead < size) + { + if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength) + { + dataChunkOffset = 0; + dataChunkIndex++; + pDataChunk++; + } + else + { + byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup; + + uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset; + if (bytesToRead > (uint)size) + { + bytesToRead = (uint)size; + } + for (uint i = 0; i < bytesToRead; i++) + { + *(pTo++) = *(pFrom++); + } + dataRead += bytesToRead; + dataChunkOffset += bytesToRead; + } + } + } + } + // we're finished. + if (dataChunkIndex == request->EntityChunkCount) + { + dataChunkIndex = -1; + } + return dataRead; + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs index 7538ba9b2c..7402c4ef8f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class RawUrlHelper { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs index 431f23558b..47759a41c5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs @@ -11,7 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Primitives; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class RequestHeaders diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs similarity index 57% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs index 3d6f701b61..0f87c3565a 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs @@ -6,20 +6,26 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { - internal partial class RequestHeaders : IDictionary + internal partial class RequestHeaders : IHeaderDictionary { private IDictionary _extra; private NativeRequestContext _requestMemoryBlob; + private long? _contentLength; + private StringValues _contentLengthText; internal RequestHeaders(NativeRequestContext requestMemoryBlob) { _requestMemoryBlob = requestMemoryBlob; } + public bool IsReadOnly { get; internal set; } + private IDictionary Extra { get @@ -43,6 +49,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } set { + ThrowIfReadOnly(); if (!PropertiesTrySetValue(key, value)) { Extra[key] = value; @@ -131,6 +138,96 @@ namespace Microsoft.AspNetCore.Server.HttpSys get { return false; } } + long? IHeaderDictionary.ContentLength + { + get + { + long value; + var rawValue = this[HttpKnownHeaderNames.ContentLength]; + + if (_contentLengthText.Equals(rawValue)) + { + return _contentLength; + } + + if (rawValue.Count == 1 && + !string.IsNullOrWhiteSpace(rawValue[0]) && + HeaderUtilities.TryParseNonNegativeInt64(new StringSegment(rawValue[0]).Trim(), out value)) + { + _contentLengthText = rawValue; + _contentLength = value; + return value; + } + + return null; + } + set + { + ThrowIfReadOnly(); + + if (value.HasValue) + { + if (value.Value < 0) + { + throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative."); + } + _contentLengthText = HeaderUtilities.FormatNonNegativeInt64(value.Value); + this[HttpKnownHeaderNames.ContentLength] = _contentLengthText; + _contentLength = value; + } + else + { + Remove(HttpKnownHeaderNames.ContentLength); + _contentLengthText = StringValues.Empty; + _contentLength = null; + } + } + } + + public StringValues this[string key] + { + get + { + StringValues values; + return TryGetValue(key, out values) ? values : StringValues.Empty; + } + set + { + if (StringValues.IsNullOrEmpty(value)) + { + Remove(key); + } + else + { + Extra[key] = value; + } + } + } + + StringValues IHeaderDictionary.this[string key] + { + get + { + if (PropertiesTryGetValue(key, out var value)) + { + return value; + } + + if (Extra.TryGetValue(key, out value)) + { + return value; + } + return StringValues.Empty; + } + set + { + if (!PropertiesTrySetValue(key, value)) + { + Extra[key] = value; + } + } + } + bool ICollection>.Remove(KeyValuePair item) { return ((IDictionary)this).Contains(item) && @@ -146,5 +243,23 @@ namespace Microsoft.AspNetCore.Server.HttpSys { return ((IDictionary)this).GetEnumerator(); } + + private void ThrowIfReadOnly() + { + if (IsReadOnly) + { + throw new InvalidOperationException("The response headers cannot be modified because the response has already started."); + } + } + + public IEnumerable GetValues(string key) + { + StringValues values; + if (TryGetValue(key, out values)) + { + return HeaderParser.SplitValues(values); + } + return HeaderParser.Empty; + } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs index 813970025e..6308d6d8ea 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs @@ -4,7 +4,7 @@ using System; using System.Text; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { // We don't use the cooked URL because http.sys unescapes all percent-encoded values. However, // we also can't just use the raw Uri, since http.sys supports not only UTF-8, but also ANSI/DBCS and diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs similarity index 85% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs index b7c325bc01..5154a0e9da 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal enum SslStatus : byte { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs index 3057e138e7..efb191760e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs @@ -3,9 +3,10 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -16,12 +17,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys private TaskCompletionSource _tcs; private HttpSysListener _server; private NativeRequestContext _nativeRequestContext; + private const int DefaultBufferSize = 4096; + private const int AlignmentPadding = 8; internal AsyncAcceptContext(HttpSysListener server) { _server = server; _tcs = new TaskCompletionSource(); - _nativeRequestContext = new NativeRequestContext(this); + AllocateNativeRequest(); } internal Task Task @@ -68,12 +71,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys { // at this point we have received an unmanaged HTTP_REQUEST and memoryBlob // points to it we need to hook up our authentication handling code here. - bool stoleBlob = false; try { if (server.ValidateRequest(asyncResult._nativeRequestContext) && server.ValidateAuth(asyncResult._nativeRequestContext)) { - stoleBlob = true; RequestContext requestContext = new RequestContext(server, asyncResult._nativeRequestContext); asyncResult.Tcs.TrySetResult(requestContext); complete = true; @@ -81,20 +82,21 @@ namespace Microsoft.AspNetCore.Server.HttpSys } finally { - if (stoleBlob) + // The request has been handed to the user, which means this code can't reuse the blob. Reset it here. + if (complete) { - // The request has been handed to the user, which means this code can't reuse the blob. Reset it here. - asyncResult._nativeRequestContext = complete ? null : new NativeRequestContext(asyncResult); + asyncResult._nativeRequestContext = null; } else { - asyncResult._nativeRequestContext.Reset(); + asyncResult.AllocateNativeRequest(size: asyncResult._nativeRequestContext.Size); } } } else { - asyncResult._nativeRequestContext.Reset(asyncResult._nativeRequestContext.RequestId, numBytes); + // (uint)backingBuffer.Length - AlignmentPadding + asyncResult.AllocateNativeRequest(numBytes, asyncResult._nativeRequestContext.RequestId); } // We need to issue a new request, either because auth failed, or because our buffer was too small the first time. @@ -147,7 +149,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys statusCode = HttpApi.HttpReceiveHttpRequest( Server.RequestQueue.Handle, _nativeRequestContext.RequestId, - (uint)HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, + (uint)HttpApiTypes.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, _nativeRequestContext.NativeRequest, _nativeRequestContext.Size, &bytesTransferred, @@ -165,7 +167,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys { // the buffer was not big enough to fit the headers, we need // to read the RequestId returned, allocate a new buffer of the required size - _nativeRequestContext.Reset(_nativeRequestContext.RequestId, bytesTransferred); + // (uint)backingBuffer.Length - AlignmentPadding + AllocateNativeRequest(bytesTransferred); retry = true; } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS @@ -179,6 +182,36 @@ namespace Microsoft.AspNetCore.Server.HttpSys return statusCode; } + internal void AllocateNativeRequest(uint? size = null, ulong requestId = 0) + { + //Debug.Assert(size != 0, "unexpected size"); + + // We can't reuse overlapped objects + uint newSize = size.HasValue ? size.Value : DefaultBufferSize; + var backingBuffer = new byte[newSize + AlignmentPadding]; + + var boundHandle = Server.RequestQueue.BoundHandle; + var nativeOverlapped = new SafeNativeOverlapped(boundHandle, + boundHandle.AllocateNativeOverlapped(IOCallback, this, backingBuffer)); + + var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(backingBuffer, 0); + + // TODO: + // Apparently the HttpReceiveHttpRequest memory alignment requirements for non - ARM processors + // are different than for ARM processors. We have seen 4 - byte - aligned buffers allocated on + // virtual x64/x86 machines which were accepted by HttpReceiveHttpRequest without errors. In + // these cases the buffer alignment may cause reading values at invalid offset. Setting buffer + // alignment to 0 for now. + // + // _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07); + + var bufferAlignment = 0; + + var nativeRequest = (HttpApiTypes.HTTP_REQUEST*)(requestAddress + bufferAlignment); + // nativeRequest + _nativeRequestContext = new NativeRequestContext(nativeOverlapped, bufferAlignment, nativeRequest, backingBuffer, requestId); + } + public object AsyncState { get { return _tcs.Task.AsyncState; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs index e4b728dcd4..b9594d1143 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Principal; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Server.HttpSys @@ -21,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public sealed class AuthenticationManager { private static readonly int AuthInfoSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private UrlGroup _urlGroup; private AuthenticationSchemes _authSchemes; @@ -62,12 +63,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys return; } - HttpApi.HTTP_SERVER_AUTHENTICATION_INFO authInfo = - new HttpApi.HTTP_SERVER_AUTHENTICATION_INFO(); + HttpApiTypes.HTTP_SERVER_AUTHENTICATION_INFO authInfo = + new HttpApiTypes.HTTP_SERVER_AUTHENTICATION_INFO(); - authInfo.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; - var authSchemes = (HttpApi.HTTP_AUTH_TYPES)_authSchemes; - if (authSchemes != HttpApi.HTTP_AUTH_TYPES.NONE) + authInfo.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + var authSchemes = (HttpApiTypes.HTTP_AUTH_TYPES)_authSchemes; + if (authSchemes != HttpApiTypes.HTTP_AUTH_TYPES.NONE) { authInfo.AuthSchemes = authSchemes; @@ -81,7 +82,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys IntPtr infoptr = new IntPtr(&authInfo); _urlGroup.SetProperty( - HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, + HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty, infoptr, (uint)AuthInfoSize); } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs index 56d1e4356d..2c70016e3f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys @@ -56,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys throw new PlatformNotSupportedException(); } - Debug.Assert(HttpApi.ApiVersion == HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version"); + Debug.Assert(HttpApi.ApiVersion == HttpApiTypes.HTTP_API_VERSION.Version20, "Invalid Http api version"); Options = options; @@ -317,8 +318,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys private unsafe void SendError(ulong requestId, int httpStatusCode, IList authChallenges) { - HttpApi.HTTP_RESPONSE_V2 httpResponse = new HttpApi.HTTP_RESPONSE_V2(); - httpResponse.Response_V1.Version = new HttpApi.HTTP_VERSION(); + HttpApiTypes.HTTP_RESPONSE_V2 httpResponse = new HttpApiTypes.HTTP_RESPONSE_V2(); + httpResponse.Response_V1.Version = new HttpApiTypes.HTTP_VERSION(); httpResponse.Response_V1.Version.MajorVersion = (ushort)1; httpResponse.Response_V1.Version.MinorVersion = (ushort)1; @@ -331,25 +332,25 @@ namespace Microsoft.AspNetCore.Server.HttpSys { pinnedHeaders = new List(); - HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; - knownHeaderInfo = new HttpApi.HTTP_RESPONSE_INFO[1]; + HttpApiTypes.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; + knownHeaderInfo = new HttpApiTypes.HTTP_RESPONSE_INFO[1]; gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - httpResponse.pResponseInfo = (HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); + httpResponse.pResponseInfo = (HttpApiTypes.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); - knownHeaderInfo[httpResponse.ResponseInfoCount].Type = HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; + knownHeaderInfo[httpResponse.ResponseInfoCount].Type = HttpApiTypes.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[httpResponse.ResponseInfoCount].Length = - (uint)Marshal.SizeOf(); + (uint)Marshal.SizeOf(); - HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); + HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS(); - header.HeaderId = HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderWwwAuthenticate; - header.Flags = HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // The docs say this is for www-auth only. + header.HeaderId = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderWwwAuthenticate; + header.Flags = HttpApiTypes.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // The docs say this is for www-auth only. - HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApi.HTTP_KNOWN_HEADER[authChallenges.Count]; + HttpApiTypes.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApiTypes.HTTP_KNOWN_HEADER[authChallenges.Count]; gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - header.KnownHeaders = (HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + header.KnownHeaders = (HttpApiTypes.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); for (int headerValueIndex = 0; headerValueIndex < authChallenges.Count; headerValueIndex++) { @@ -359,14 +360,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - nativeHeaderValues[header.KnownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + nativeHeaderValues[header.KnownHeaderCount].pRawValue = (byte*)gcHandle.AddrOfPinnedObject(); header.KnownHeaderCount++; } // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - knownHeaderInfo[0].pInfo = (HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); + knownHeaderInfo[0].pInfo = (HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); httpResponse.ResponseInfoCount = 1; } @@ -378,13 +379,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys byte[] byteReason = HeaderEncoding.GetBytes(statusDescription); fixed (byte* pReason = byteReason) { - httpResponse.Response_V1.pReason = (sbyte*)pReason; + httpResponse.Response_V1.pReason = (byte*)pReason; httpResponse.Response_V1.ReasonLength = (ushort)byteReason.Length; byte[] byteContentLength = new byte[] { (byte)'0' }; fixed (byte* pContentLength = byteContentLength) { - (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength; + (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (byte*)pContentLength; (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; httpResponse.Response_V1.Headers.UnknownHeaderCount = 0; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 00a28df87c..2b06066936 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index a7373c095c..592368a043 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -9,6 +9,10 @@ aspnetcore;weblistener;httpsys + + + + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs deleted file mode 100644 index 9f4a7063be..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - /// - /// - /// Specifies the address families. - /// - /// - internal enum AddressFamily - { - /// - /// [To be supplied.] - /// - Unknown = -1, // Unknown - - /// - /// [To be supplied.] - /// - Unspecified = 0, // unspecified - - /// - /// [To be supplied.] - /// - Unix = 1, // local to host (pipes, portals) - - /// - /// [To be supplied.] - /// - InterNetwork = 2, // internetwork: UDP, TCP, etc. - - /// - /// [To be supplied.] - /// - ImpLink = 3, // arpanet imp addresses - - /// - /// [To be supplied.] - /// - Pup = 4, // pup protocols: e.g. BSP - - /// - /// [To be supplied.] - /// - Chaos = 5, // mit CHAOS protocols - - /// - /// [To be supplied.] - /// - NS = 6, // XEROX NS protocols - - /// - /// [To be supplied.] - /// - Ipx = NS, // IPX and SPX - - /// - /// [To be supplied.] - /// - Iso = 7, // ISO protocols - - /// - /// [To be supplied.] - /// - Osi = Iso, // OSI is ISO - - /// - /// [To be supplied.] - /// - Ecma = 8, // european computer manufacturers - - /// - /// [To be supplied.] - /// - DataKit = 9, // datakit protocols - - /// - /// [To be supplied.] - /// - Ccitt = 10, // CCITT protocols, X.25 etc - - /// - /// [To be supplied.] - /// - Sna = 11, // IBM SNA - - /// - /// [To be supplied.] - /// - DecNet = 12, // DECnet - - /// - /// [To be supplied.] - /// - DataLink = 13, // Direct data link interface - - /// - /// [To be supplied.] - /// - Lat = 14, // LAT - - /// - /// [To be supplied.] - /// - HyperChannel = 15, // NSC Hyperchannel - - /// - /// [To be supplied.] - /// - AppleTalk = 16, // AppleTalk - - /// - /// [To be supplied.] - /// - NetBios = 17, // NetBios-style addresses - - /// - /// [To be supplied.] - /// - VoiceView = 18, // VoiceView - - /// - /// [To be supplied.] - /// - FireFox = 19, // FireFox - - /// - /// [To be supplied.] - /// - Banyan = 21, // Banyan - - /// - /// [To be supplied.] - /// - Atm = 22, // Native ATM Services - - /// - /// [To be supplied.] - /// - InterNetworkV6 = 23, // Internetwork Version 6 - - /// - /// [To be supplied.] - /// - Cluster = 24, // Microsoft Wolfpack - - /// - /// [To be supplied.] - /// - Ieee12844 = 25, // IEEE 1284.4 WG AF - - /// - /// [To be supplied.] - /// - Irda = 26, // IrDA - - /// - /// [To be supplied.] - /// - NetworkDesigners = 28, // Network Designers OSI & gateway enabled protocols - - /// - /// [To be supplied.] - /// - Max = 29, // Max - }; // enum AddressFamily -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs index f9a3a7c0e5..ecef12b989 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.ComponentModel; using System.Diagnostics; using System.Threading; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs index 94bc558af5..1dc97ef20d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs @@ -2,9 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Runtime.InteropServices; -using Microsoft.Extensions.Primitives; +using Microsoft.AspNetCore.HttpSys.Internal; +using static Microsoft.AspNetCore.HttpSys.Internal.HttpApiTypes; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -70,688 +70,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); - internal enum HTTP_API_VERSION - { - Invalid, - Version10, - Version20, - } - - // see http.w for definitions - internal enum HTTP_SERVER_PROPERTY - { - HttpServerAuthenticationProperty, - HttpServerLoggingProperty, - HttpServerQosProperty, - HttpServerTimeoutsProperty, - HttpServerQueueLengthProperty, - HttpServerStateProperty, - HttpServer503VerbosityProperty, - HttpServerBindingProperty, - HttpServerExtendedAuthenticationProperty, - HttpServerListenEndpointProperty, - HttpServerChannelBindProperty, - HttpServerProtectionLevelProperty, - } - - // Currently only one request info type is supported but the enum is for future extensibility. - - internal enum HTTP_REQUEST_INFO_TYPE - { - HttpRequestInfoTypeAuth, - HttpRequestInfoTypeChannelBind, - HttpRequestInfoTypeSslProtocol, - HttpRequestInfoTypeSslTokenBinding - } - - internal enum HTTP_RESPONSE_INFO_TYPE - { - HttpResponseInfoTypeMultipleKnownHeaders, - HttpResponseInfoTypeAuthenticationProperty, - HttpResponseInfoTypeQosProperty, - } - - internal enum HTTP_TIMEOUT_TYPE - { - EntityBody, - DrainEntityBody, - RequestQueue, - IdleConnection, - HeaderWait, - MinSendRate, - } - - internal const int MaxTimeout = 6; - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_VERSION - { - internal ushort MajorVersion; - internal ushort MinorVersion; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_KNOWN_HEADER - { - internal ushort RawValueLength; - internal sbyte* pRawValue; - } - - [StructLayout(LayoutKind.Explicit)] - internal struct HTTP_DATA_CHUNK - { - [FieldOffset(0)] - internal HTTP_DATA_CHUNK_TYPE DataChunkType; - - [FieldOffset(8)] - internal FromMemory fromMemory; - - [FieldOffset(8)] - internal FromFileHandle fromFile; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct FromMemory - { - // 4 bytes for 32bit, 8 bytes for 64bit - internal IntPtr pBuffer; - internal uint BufferLength; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct FromFileHandle - { - internal ulong offset; - internal ulong count; - internal IntPtr fileHandle; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTPAPI_VERSION - { - internal ushort HttpApiMajorVersion; - internal ushort HttpApiMinorVersion; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_COOKED_URL - { - internal ushort FullUrlLength; - internal ushort HostLength; - internal ushort AbsPathLength; - internal ushort QueryStringLength; - internal ushort* pFullUrl; - internal ushort* pHost; - internal ushort* pAbsPath; - internal ushort* pQueryString; - } - - // Only cache unauthorized GETs + HEADs. - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_CACHE_POLICY - { - internal HTTP_CACHE_POLICY_TYPE Policy; - internal uint SecondsToLive; - } - - internal enum HTTP_CACHE_POLICY_TYPE : int - { - HttpCachePolicyNocache = 0, - HttpCachePolicyUserInvalidates = 1, - HttpCachePolicyTimeToLive = 2, - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SOCKADDR - { - internal ushort sa_family; - internal byte sa_data; - internal byte sa_data_02; - internal byte sa_data_03; - internal byte sa_data_04; - internal byte sa_data_05; - internal byte sa_data_06; - internal byte sa_data_07; - internal byte sa_data_08; - internal byte sa_data_09; - internal byte sa_data_10; - internal byte sa_data_11; - internal byte sa_data_12; - internal byte sa_data_13; - internal byte sa_data_14; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_TRANSPORT_ADDRESS - { - internal SOCKADDR* pRemoteAddress; - internal SOCKADDR* pLocalAddress; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SSL_CLIENT_CERT_INFO - { - internal uint CertFlags; - internal uint CertEncodedSize; - internal byte* pCertEncoded; - internal void* Token; - internal byte CertDeniedByMapper; - } - - internal enum HTTP_SERVICE_BINDING_TYPE : uint - { - HttpServiceBindingTypeNone = 0, - HttpServiceBindingTypeW, - HttpServiceBindingTypeA - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SERVICE_BINDING_BASE - { - internal HTTP_SERVICE_BINDING_TYPE Type; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_CHANNEL_BIND_STATUS - { - internal IntPtr ServiceName; - internal IntPtr ChannelToken; - internal uint ChannelTokenSize; - internal uint Flags; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_UNKNOWN_HEADER - { - internal ushort NameLength; - internal ushort RawValueLength; - internal sbyte* pName; - internal sbyte* pRawValue; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SSL_INFO - { - internal ushort ServerCertKeySize; - internal ushort ConnectionKeySize; - internal uint ServerCertIssuerSize; - internal uint ServerCertSubjectSize; - internal sbyte* pServerCertIssuer; - internal sbyte* pServerCertSubject; - internal HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo; - internal uint SslClientCertNegotiated; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_RESPONSE_HEADERS - { - internal ushort UnknownHeaderCount; - internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; - internal ushort TrailerCount; - internal HTTP_UNKNOWN_HEADER* pTrailers; - internal HTTP_KNOWN_HEADER KnownHeaders; - internal HTTP_KNOWN_HEADER KnownHeaders_02; - internal HTTP_KNOWN_HEADER KnownHeaders_03; - internal HTTP_KNOWN_HEADER KnownHeaders_04; - internal HTTP_KNOWN_HEADER KnownHeaders_05; - internal HTTP_KNOWN_HEADER KnownHeaders_06; - internal HTTP_KNOWN_HEADER KnownHeaders_07; - internal HTTP_KNOWN_HEADER KnownHeaders_08; - internal HTTP_KNOWN_HEADER KnownHeaders_09; - internal HTTP_KNOWN_HEADER KnownHeaders_10; - internal HTTP_KNOWN_HEADER KnownHeaders_11; - internal HTTP_KNOWN_HEADER KnownHeaders_12; - internal HTTP_KNOWN_HEADER KnownHeaders_13; - internal HTTP_KNOWN_HEADER KnownHeaders_14; - internal HTTP_KNOWN_HEADER KnownHeaders_15; - internal HTTP_KNOWN_HEADER KnownHeaders_16; - internal HTTP_KNOWN_HEADER KnownHeaders_17; - internal HTTP_KNOWN_HEADER KnownHeaders_18; - internal HTTP_KNOWN_HEADER KnownHeaders_19; - internal HTTP_KNOWN_HEADER KnownHeaders_20; - internal HTTP_KNOWN_HEADER KnownHeaders_21; - internal HTTP_KNOWN_HEADER KnownHeaders_22; - internal HTTP_KNOWN_HEADER KnownHeaders_23; - internal HTTP_KNOWN_HEADER KnownHeaders_24; - internal HTTP_KNOWN_HEADER KnownHeaders_25; - internal HTTP_KNOWN_HEADER KnownHeaders_26; - internal HTTP_KNOWN_HEADER KnownHeaders_27; - internal HTTP_KNOWN_HEADER KnownHeaders_28; - internal HTTP_KNOWN_HEADER KnownHeaders_29; - internal HTTP_KNOWN_HEADER KnownHeaders_30; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_HEADERS - { - internal ushort UnknownHeaderCount; - internal HTTP_UNKNOWN_HEADER* pUnknownHeaders; - internal ushort TrailerCount; - internal HTTP_UNKNOWN_HEADER* pTrailers; - internal HTTP_KNOWN_HEADER KnownHeaders; - internal HTTP_KNOWN_HEADER KnownHeaders_02; - internal HTTP_KNOWN_HEADER KnownHeaders_03; - internal HTTP_KNOWN_HEADER KnownHeaders_04; - internal HTTP_KNOWN_HEADER KnownHeaders_05; - internal HTTP_KNOWN_HEADER KnownHeaders_06; - internal HTTP_KNOWN_HEADER KnownHeaders_07; - internal HTTP_KNOWN_HEADER KnownHeaders_08; - internal HTTP_KNOWN_HEADER KnownHeaders_09; - internal HTTP_KNOWN_HEADER KnownHeaders_10; - internal HTTP_KNOWN_HEADER KnownHeaders_11; - internal HTTP_KNOWN_HEADER KnownHeaders_12; - internal HTTP_KNOWN_HEADER KnownHeaders_13; - internal HTTP_KNOWN_HEADER KnownHeaders_14; - internal HTTP_KNOWN_HEADER KnownHeaders_15; - internal HTTP_KNOWN_HEADER KnownHeaders_16; - internal HTTP_KNOWN_HEADER KnownHeaders_17; - internal HTTP_KNOWN_HEADER KnownHeaders_18; - internal HTTP_KNOWN_HEADER KnownHeaders_19; - internal HTTP_KNOWN_HEADER KnownHeaders_20; - internal HTTP_KNOWN_HEADER KnownHeaders_21; - internal HTTP_KNOWN_HEADER KnownHeaders_22; - internal HTTP_KNOWN_HEADER KnownHeaders_23; - internal HTTP_KNOWN_HEADER KnownHeaders_24; - internal HTTP_KNOWN_HEADER KnownHeaders_25; - internal HTTP_KNOWN_HEADER KnownHeaders_26; - internal HTTP_KNOWN_HEADER KnownHeaders_27; - internal HTTP_KNOWN_HEADER KnownHeaders_28; - internal HTTP_KNOWN_HEADER KnownHeaders_29; - internal HTTP_KNOWN_HEADER KnownHeaders_30; - internal HTTP_KNOWN_HEADER KnownHeaders_31; - internal HTTP_KNOWN_HEADER KnownHeaders_32; - internal HTTP_KNOWN_HEADER KnownHeaders_33; - internal HTTP_KNOWN_HEADER KnownHeaders_34; - internal HTTP_KNOWN_HEADER KnownHeaders_35; - internal HTTP_KNOWN_HEADER KnownHeaders_36; - internal HTTP_KNOWN_HEADER KnownHeaders_37; - internal HTTP_KNOWN_HEADER KnownHeaders_38; - internal HTTP_KNOWN_HEADER KnownHeaders_39; - internal HTTP_KNOWN_HEADER KnownHeaders_40; - internal HTTP_KNOWN_HEADER KnownHeaders_41; - } - - internal enum HTTP_VERB : int - { - HttpVerbUnparsed = 0, - HttpVerbUnknown = 1, - HttpVerbInvalid = 2, - HttpVerbOPTIONS = 3, - HttpVerbGET = 4, - HttpVerbHEAD = 5, - HttpVerbPOST = 6, - HttpVerbPUT = 7, - HttpVerbDELETE = 8, - HttpVerbTRACE = 9, - HttpVerbCONNECT = 10, - HttpVerbTRACK = 11, - HttpVerbMOVE = 12, - HttpVerbCOPY = 13, - HttpVerbPROPFIND = 14, - HttpVerbPROPPATCH = 15, - HttpVerbMKCOL = 16, - HttpVerbLOCK = 17, - HttpVerbUNLOCK = 18, - HttpVerbSEARCH = 19, - HttpVerbMaximum = 20, - } - - internal static readonly string[] HttpVerbs = new string[] - { - null, - "Unknown", - "Invalid", - "OPTIONS", - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "TRACE", - "CONNECT", - "TRACK", - "MOVE", - "COPY", - "PROPFIND", - "PROPPATCH", - "MKCOL", - "LOCK", - "UNLOCK", - "SEARCH", - }; - - internal enum HTTP_DATA_CHUNK_TYPE : int - { - HttpDataChunkFromMemory = 0, - HttpDataChunkFromFileHandle = 1, - HttpDataChunkFromFragmentCache = 2, - HttpDataChunkMaximum = 3, - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_RESPONSE_INFO - { - internal HTTP_RESPONSE_INFO_TYPE Type; - internal uint Length; - internal HTTP_MULTIPLE_KNOWN_HEADERS* pInfo; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_RESPONSE - { - internal uint Flags; - internal HTTP_VERSION Version; - internal ushort StatusCode; - internal ushort ReasonLength; - internal sbyte* pReason; - internal HTTP_RESPONSE_HEADERS Headers; - internal ushort EntityChunkCount; - internal HTTP_DATA_CHUNK* pEntityChunks; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_RESPONSE_V2 - { - internal HTTP_RESPONSE Response_V1; - internal ushort ResponseInfoCount; - internal HTTP_RESPONSE_INFO* pResponseInfo; - } - - internal enum HTTP_RESPONSE_INFO_FLAGS : uint - { - None = 0, - PreserveOrder = 1, - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_MULTIPLE_KNOWN_HEADERS - { - internal HTTP_RESPONSE_HEADER_ID.Enum HeaderId; - internal HTTP_RESPONSE_INFO_FLAGS Flags; - internal ushort KnownHeaderCount; - internal HTTP_KNOWN_HEADER* KnownHeaders; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_AUTH_INFO - { - internal HTTP_AUTH_STATUS AuthStatus; - internal uint SecStatus; - internal uint Flags; - internal HTTP_REQUEST_AUTH_TYPE AuthType; - internal IntPtr AccessToken; - internal uint ContextAttributes; - internal uint PackedContextLength; - internal uint PackedContextType; - internal IntPtr PackedContext; - internal uint MutualAuthDataLength; - internal char* pMutualAuthData; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_INFO - { - internal HTTP_REQUEST_INFO_TYPE InfoType; - internal uint InfoLength; - internal HTTP_REQUEST_AUTH_INFO* pInfo; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST - { - internal uint Flags; - internal ulong ConnectionId; - internal ulong RequestId; - internal ulong UrlContext; - internal HTTP_VERSION Version; - internal HTTP_VERB Verb; - internal ushort UnknownVerbLength; - internal ushort RawUrlLength; - internal sbyte* pUnknownVerb; - internal sbyte* pRawUrl; - internal HTTP_COOKED_URL CookedUrl; - internal HTTP_TRANSPORT_ADDRESS Address; - internal HTTP_REQUEST_HEADERS Headers; - internal ulong BytesReceived; - internal ushort EntityChunkCount; - internal HTTP_DATA_CHUNK* pEntityChunks; - internal ulong RawConnectionId; - internal HTTP_SSL_INFO* pSslInfo; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_V2 - { - internal HTTP_REQUEST Request; - internal ushort RequestInfoCount; - internal HTTP_REQUEST_INFO* pRequestInfo; - } - - internal enum HTTP_AUTH_STATUS - { - HttpAuthStatusSuccess, - HttpAuthStatusNotAuthenticated, - HttpAuthStatusFailure, - } - - internal enum HTTP_REQUEST_AUTH_TYPE - { - HttpRequestAuthTypeNone = 0, - HttpRequestAuthTypeBasic, - HttpRequestAuthTypeDigest, - HttpRequestAuthTypeNTLM, - HttpRequestAuthTypeNegotiate, - HttpRequestAuthTypeKerberos - } - - internal enum HTTP_QOS_SETTING_TYPE - { - HttpQosSettingTypeBandwidth, - HttpQosSettingTypeConnectionLimit, - HttpQosSettingTypeFlowRate - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SERVER_AUTHENTICATION_INFO - { - internal HTTP_FLAGS Flags; - internal HTTP_AUTH_TYPES AuthSchemes; - internal bool ReceiveMutualAuth; - internal bool ReceiveContextHandle; - internal bool DisableNTLMCredentialCaching; - internal ulong ExFlags; - HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS DigestParams; - HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS BasicParams; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS - { - internal ushort DomainNameLength; - internal char* DomainName; - internal ushort RealmLength; - internal char* Realm; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS - { - ushort RealmLength; - char* Realm; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_REQUEST_TOKEN_BINDING_INFO - { - public byte* TokenBinding; - public uint TokenBindingSize; - - public byte* TlsUnique; - public uint TlsUniqueSize; - - public char* KeyType; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_TIMEOUT_LIMIT_INFO - { - internal HTTP_FLAGS Flags; - internal ushort EntityBody; - internal ushort DrainEntityBody; - internal ushort RequestQueue; - internal ushort IdleConnection; - internal ushort HeaderWait; - internal uint MinSendRate; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_BINDING_INFO - { - internal HTTP_FLAGS Flags; - internal IntPtr RequestQueueHandle; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_CONNECTION_LIMIT_INFO - { - internal HTTP_FLAGS Flags; - internal uint MaxConnections; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HTTP_QOS_SETTING_INFO - { - internal HTTP_QOS_SETTING_TYPE QosType; - internal IntPtr QosSetting; - } - - // see http.w for definitions - [Flags] - internal enum HTTP_FLAGS : uint - { - NONE = 0x00000000, - HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY = 0x00000001, - HTTP_RECEIVE_SECURE_CHANNEL_TOKEN = 0x00000001, - HTTP_SEND_RESPONSE_FLAG_DISCONNECT = 0x00000001, - HTTP_SEND_RESPONSE_FLAG_MORE_DATA = 0x00000002, - HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA = 0x00000004, - HTTP_SEND_RESPONSE_FLAG_RAW_HEADER = 0x00000004, - HTTP_SEND_REQUEST_FLAG_MORE_DATA = 0x00000001, - HTTP_PROPERTY_FLAG_PRESENT = 0x00000001, - HTTP_INITIALIZE_SERVER = 0x00000001, - HTTP_INITIALIZE_CBT = 0x00000004, - HTTP_SEND_RESPONSE_FLAG_OPAQUE = 0x00000040, - } - - [Flags] - internal enum HTTP_AUTH_TYPES : uint - { - NONE = 0x00000000, - HTTP_AUTH_ENABLE_BASIC = 0x00000001, - HTTP_AUTH_ENABLE_DIGEST = 0x00000002, - HTTP_AUTH_ENABLE_NTLM = 0x00000004, - HTTP_AUTH_ENABLE_NEGOTIATE = 0x00000008, - HTTP_AUTH_ENABLE_KERBEROS = 0x00000010, - } - - internal static class HTTP_RESPONSE_HEADER_ID - { - private static string[] _strings = - { - "Cache-Control", - "Connection", - "Date", - "Keep-Alive", - "Pragma", - "Trailer", - "Transfer-Encoding", - "Upgrade", - "Via", - "Warning", - - "Allow", - "Content-Length", - "Content-Type", - "Content-Encoding", - "Content-Language", - "Content-Location", - "Content-MD5", - "Content-Range", - "Expires", - "Last-Modified", - - "Accept-Ranges", - "Age", - "ETag", - "Location", - "Proxy-Authenticate", - "Retry-After", - "Server", - "Set-Cookie", - "Vary", - "WWW-Authenticate", - }; - - private static Dictionary _lookupTable = CreateLookupTable(); - - private static Dictionary CreateLookupTable() - { - Dictionary lookupTable = new Dictionary((int)Enum.HttpHeaderResponseMaximum, StringComparer.OrdinalIgnoreCase); - for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++) - { - lookupTable.Add(_strings[i], i); - } - return lookupTable; - } - - internal static int IndexOfKnownHeader(string HeaderName) - { - int index; - return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1; - } - - internal enum Enum - { - HttpHeaderCacheControl = 0, // general-header [section 4.5] - HttpHeaderConnection = 1, // general-header [section 4.5] - HttpHeaderDate = 2, // general-header [section 4.5] - HttpHeaderKeepAlive = 3, // general-header [not in rfc] - HttpHeaderPragma = 4, // general-header [section 4.5] - HttpHeaderTrailer = 5, // general-header [section 4.5] - HttpHeaderTransferEncoding = 6, // general-header [section 4.5] - HttpHeaderUpgrade = 7, // general-header [section 4.5] - HttpHeaderVia = 8, // general-header [section 4.5] - HttpHeaderWarning = 9, // general-header [section 4.5] - - HttpHeaderAllow = 10, // entity-header [section 7.1] - HttpHeaderContentLength = 11, // entity-header [section 7.1] - HttpHeaderContentType = 12, // entity-header [section 7.1] - HttpHeaderContentEncoding = 13, // entity-header [section 7.1] - HttpHeaderContentLanguage = 14, // entity-header [section 7.1] - HttpHeaderContentLocation = 15, // entity-header [section 7.1] - HttpHeaderContentMd5 = 16, // entity-header [section 7.1] - HttpHeaderContentRange = 17, // entity-header [section 7.1] - HttpHeaderExpires = 18, // entity-header [section 7.1] - HttpHeaderLastModified = 19, // entity-header [section 7.1] - - // Response Headers - - HttpHeaderAcceptRanges = 20, // response-header [section 6.2] - HttpHeaderAge = 21, // response-header [section 6.2] - HttpHeaderEtag = 22, // response-header [section 6.2] - HttpHeaderLocation = 23, // response-header [section 6.2] - HttpHeaderProxyAuthenticate = 24, // response-header [section 6.2] - HttpHeaderRetryAfter = 25, // response-header [section 6.2] - HttpHeaderServer = 26, // response-header [section 6.2] - HttpHeaderSetCookie = 27, // response-header [not in rfc] - HttpHeaderVary = 28, // response-header [section 6.2] - HttpHeaderWwwAuthenticate = 29, // response-header [section 6.2] - - HttpHeaderResponseMaximum = 30, - - HttpHeaderMaximum = 41 - } - } private static HTTPAPI_VERSION version; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs index 46c725b193..6fac23f67f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Win32.SafeHandles; namespace Microsoft.AspNetCore.Server.HttpSys diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs index 4ed550c1d6..903e4d9065 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs @@ -3,6 +3,7 @@ using System; using System.Threading; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Win32.SafeHandles; namespace Microsoft.AspNetCore.Server.HttpSys @@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { serverSessionId = id; - // This class uses no real handle so we need to set a dummy handle. Otherwise, IsInvalid always remains + // This class uses no real handle so we need to set a dummy handle. Otherwise, IsInvalid always remains // true. SetHandle(new IntPtr(1)); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs index 4468f7029e..29f43b6fd5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.InteropServices; using System.Threading; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys @@ -11,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal class RequestQueue { private static readonly int BindingInfoSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private readonly UrlGroup _urlGroup; private readonly ILogger _logger; @@ -54,13 +55,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys // Set the association between request queue and url group. After this, requests for registered urls will // get delivered to this request queue. - var info = new HttpApi.HTTP_BINDING_INFO(); - info.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + var info = new HttpApiTypes.HTTP_BINDING_INFO(); + info.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; info.RequestQueueHandle = Handle.DangerousGetHandle(); var infoptr = new IntPtr(&info); - _urlGroup.SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + _urlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, infoptr, (uint)BindingInfoSize); } @@ -73,13 +74,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys // is fine since http.sys allows to set HttpServerBindingProperty multiple times for valid // Url groups. - var info = new HttpApi.HTTP_BINDING_INFO(); - info.Flags = HttpApi.HTTP_FLAGS.NONE; + var info = new HttpApiTypes.HTTP_BINDING_INFO(); + info.Flags = HttpApiTypes.HTTP_FLAGS.NONE; info.RequestQueueHandle = IntPtr.Zero; var infoptr = new IntPtr(&info); - _urlGroup.SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + _urlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, infoptr, (uint)BindingInfoSize, throwOnError: false); } @@ -89,7 +90,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys CheckDisposed(); var result = HttpApi.HttpSetRequestQueueProperty(Handle, - HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, + HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, new IntPtr((void*)&length), (uint)Marshal.SizeOf(), 0, IntPtr.Zero); if (result != 0) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs index 9bebb1e9c5..1d2798bd8e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs index ddb11c5240..21d17656a8 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs @@ -3,8 +3,9 @@ using System; using System.Runtime.InteropServices; -using static Microsoft.AspNetCore.Server.HttpSys.HttpApi; -using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods.TokenBinding; +using Microsoft.AspNetCore.HttpSys.Internal; +using static Microsoft.AspNetCore.HttpSys.Internal.HttpApiTypes; +using static Microsoft.AspNetCore.HttpSys.Internal.UnsafeNclNativeMethods.TokenBinding; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs index cdeaae7800..8f33c7b678 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys @@ -11,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal class UrlGroup : IDisposable { private static readonly int QosInfoSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private ServerSession _serverSession; private ILogger _logger; @@ -39,18 +40,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal unsafe void SetMaxConnections(long maxConnections) { - var connectionLimit = new HttpApi.HTTP_CONNECTION_LIMIT_INFO(); - connectionLimit.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + var connectionLimit = new HttpApiTypes.HTTP_CONNECTION_LIMIT_INFO(); + connectionLimit.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; connectionLimit.MaxConnections = (uint)maxConnections; - var qosSettings = new HttpApi.HTTP_QOS_SETTING_INFO(); - qosSettings.QosType = HttpApi.HTTP_QOS_SETTING_TYPE.HttpQosSettingTypeConnectionLimit; + var qosSettings = new HttpApiTypes.HTTP_QOS_SETTING_INFO(); + qosSettings.QosType = HttpApiTypes.HTTP_QOS_SETTING_TYPE.HttpQosSettingTypeConnectionLimit; qosSettings.QosSetting = new IntPtr(&connectionLimit); - SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerQosProperty, new IntPtr(&qosSettings), (uint)QosInfoSize); + SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerQosProperty, new IntPtr(&qosSettings), (uint)QosInfoSize); } - internal void SetProperty(HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) + internal void SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) { Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); CheckDisposed(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs index b453bed46f..74d7ed902f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs @@ -12,6 +12,7 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys @@ -23,11 +24,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys private const uint CertBoblSize = 1500; private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(WaitCallback); private static readonly int RequestChannelBindStatusSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private SafeNativeOverlapped _overlapped; private byte[] _backingBuffer; - private HttpApi.HTTP_SSL_CLIENT_CERT_INFO* _memoryBlob; + private HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* _memoryBlob; private uint _size; private TaskCompletionSource _tcs; private RequestContext _requestContext; @@ -104,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - private HttpApi.HTTP_SSL_CLIENT_CERT_INFO* RequestBlob + private HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* RequestBlob { get { @@ -134,7 +135,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var boundHandle = RequestContext.Server.RequestQueue.BoundHandle; _overlapped = new SafeNativeOverlapped(boundHandle, boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer)); - _memoryBlob = (HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); + _memoryBlob = (HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); } // When you use netsh to configure HTTP.SYS with clientcertnegotiation = enable @@ -168,7 +169,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys HttpApi.HttpReceiveClientCertificate( RequestQueueHandle, RequestContext.Request.UConnectionId, - (uint)HttpApi.HTTP_FLAGS.NONE, + (uint)HttpApiTypes.HTTP_FLAGS.NONE, RequestBlob, size, &bytesReceived, @@ -176,7 +177,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) { - HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = RequestBlob; + HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = RequestBlob; size = bytesReceived + pClientCertInfo->CertEncodedSize; Reset(size); retry = true; @@ -239,7 +240,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys // return the size of the initial cert structure. To get the full size, // we need to add the certificate encoding size as well. - HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob; + HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob; asyncResult.Reset(numBytes + pClientCertInfo->CertEncodedSize); uint bytesReceived = 0; @@ -247,7 +248,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys HttpApi.HttpReceiveClientCertificate( requestContext.Server.RequestQueue.Handle, requestContext.Request.UConnectionId, - (uint)HttpApi.HTTP_FLAGS.NONE, + (uint)HttpApiTypes.HTTP_FLAGS.NONE, asyncResult._memoryBlob, asyncResult._size, &bytesReceived, @@ -271,7 +272,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } else { - HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult._memoryBlob; + HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult._memoryBlob; if (pClientCertInfo == null) { asyncResult.Complete(0, null); @@ -374,7 +375,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys statusCode = HttpApi.HttpReceiveClientCertificate( requestQueue.Handle, connectionId, - (uint)HttpApi.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN, + (uint)HttpApiTypes.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN, blobPtr, (uint)size, &bytesReceived, @@ -418,7 +419,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private static int GetTokenOffsetFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); - IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); + IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("ChannelToken")); Debug.Assert(tokenPointer != IntPtr.Zero); return (int)IntPtrHelper.Subtract(tokenPointer, blob); } @@ -426,7 +427,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private static int GetTokenSizeFromBlob(IntPtr blob) { Debug.Assert(blob != IntPtr.Zero); - return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); + return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs deleted file mode 100644 index 7bcbb258b5..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security.Claims; -using System.Security.Principal; -using Microsoft.Extensions.Primitives; - -namespace Microsoft.AspNetCore.Server.HttpSys -{ - internal unsafe class NativeRequestContext : IDisposable - { - private const int DefaultBufferSize = 4096; - private const int AlignmentPadding = 8; - private HttpApi.HTTP_REQUEST* _nativeRequest; - private IntPtr _originalBufferAddress; - private byte[] _backingBuffer; - private int _bufferAlignment; - private SafeNativeOverlapped _nativeOverlapped; - private AsyncAcceptContext _acceptResult; - - internal NativeRequestContext(AsyncAcceptContext result) - { - _acceptResult = result; - AllocateNativeRequest(); - } - - internal SafeNativeOverlapped NativeOverlapped => _nativeOverlapped; - - internal HttpApi.HTTP_REQUEST* NativeRequest - { - get - { - Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins()."); - return _nativeRequest; - } - } - - private HttpApi.HTTP_REQUEST_V2* NativeRequestV2 - { - get - { - Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins()."); - return (HttpApi.HTTP_REQUEST_V2*)_nativeRequest; - } - } - - internal ulong RequestId - { - get { return NativeRequest->RequestId; } - set { NativeRequest->RequestId = value; } - } - - internal ulong ConnectionId => NativeRequest->ConnectionId; - - internal HttpApi.HTTP_VERB VerbId => NativeRequest->Verb; - - internal ulong UrlContext => NativeRequest->UrlContext; - - internal ushort UnknownHeaderCount => NativeRequest->Headers.UnknownHeaderCount; - - internal SslStatus SslStatus - { - get - { - return NativeRequest->pSslInfo == null ? SslStatus.Insecure : - NativeRequest->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : - SslStatus.ClientCert; - } - } - - internal uint Size - { - get { return (uint)_backingBuffer.Length - AlignmentPadding; } - } - - // ReleasePins() should be called exactly once. It must be called before Dispose() is called, which means it must be called - // before an object (Request) which closes the RequestContext on demand is returned to the application. - internal void ReleasePins() - { - Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice."); - _originalBufferAddress = (IntPtr)_nativeRequest; - _nativeRequest = null; - _nativeOverlapped?.Dispose(); - _nativeOverlapped = null; - } - - public void Dispose() - { - Debug.Assert(_nativeRequest == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins()."); - _nativeOverlapped?.Dispose(); - } - - private void SetBuffer(int size) - { - Debug.Assert(size != 0, "unexpected size"); - - _backingBuffer = new byte[size + AlignmentPadding]; - } - - private void AllocateNativeRequest(uint? size = null) - { - // We can't reuse overlapped objects - _nativeOverlapped?.Dispose(); - - uint newSize = size.HasValue ? size.Value : _backingBuffer == null ? DefaultBufferSize : Size; - SetBuffer(checked((int)newSize)); - var boundHandle = _acceptResult.Server.RequestQueue.BoundHandle; - _nativeOverlapped = new SafeNativeOverlapped(boundHandle, - boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, _backingBuffer)); - - var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0); - - // TODO: - // Apparently the HttpReceiveHttpRequest memory alignment requirements for non - ARM processors - // are different than for ARM processors. We have seen 4 - byte - aligned buffers allocated on - // virtual x64/x86 machines which were accepted by HttpReceiveHttpRequest without errors. In - // these cases the buffer alignment may cause reading values at invalid offset. Setting buffer - // alignment to 0 for now. - // - // _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07); - - _bufferAlignment = 0; - - _nativeRequest = (HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment); - } - - internal void Reset(ulong requestId = 0, uint? size = null) - { - Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::Dispose()|SetNativeRequest() called after ReleasePins()."); - AllocateNativeRequest(size); - RequestId = requestId; - } - - // These methods require the HTTP_REQUEST to still be pinned in its original location. - - internal string GetVerb() - { - var verb = NativeRequest->Verb; - if (verb > HttpApi.HTTP_VERB.HttpVerbUnknown && verb < HttpApi.HTTP_VERB.HttpVerbMaximum) - { - return HttpApi.HttpVerbs[(int)verb]; - } - else if (verb == HttpApi.HTTP_VERB.HttpVerbUnknown && NativeRequest->pUnknownVerb != null) - { - return HeaderEncoding.GetString(NativeRequest->pUnknownVerb, NativeRequest->UnknownVerbLength); - } - - return null; - } - - internal string GetRawUrl() - { - if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0) - { - return Marshal.PtrToStringAnsi((IntPtr)NativeRequest->pRawUrl, NativeRequest->RawUrlLength); - } - return null; - } - - internal byte[] GetRawUrlInBytes() - { - if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0) - { - var result = new byte[NativeRequest->RawUrlLength]; - Marshal.Copy((IntPtr)NativeRequest->pRawUrl, result, 0, NativeRequest->RawUrlLength); - - return result; - } - - return null; - } - - internal CookedUrl GetCookedUrl() - { - return new CookedUrl(NativeRequest->CookedUrl); - } - - internal Version GetVersion() - { - var major = NativeRequest->Version.MajorVersion; - var minor = NativeRequest->Version.MinorVersion; - if (major == 1 && minor == 1) - { - return Constants.V1_1; - } - else if (major == 1 && minor == 0) - { - return Constants.V1_0; - } - return new Version(major, minor); - } - - internal bool CheckAuthenticated() - { - var requestInfo = NativeRequestV2->pRequestInfo; - var infoCount = NativeRequestV2->RequestInfoCount; - - for (int i = 0; i < infoCount; i++) - { - var info = &requestInfo[i]; - if (info != null - && info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth - && info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) - { - return true; - } - } - return false; - } - - internal WindowsPrincipal GetUser() - { - var requestInfo = NativeRequestV2->pRequestInfo; - var infoCount = NativeRequestV2->RequestInfoCount; - - for (int i = 0; i < infoCount; i++) - { - var info = &requestInfo[i]; - if (info != null - && info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth - && info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess) - { - // Duplicates AccessToken - var identity = new WindowsIdentity(info->pInfo->AccessToken, - GetAuthTypeFromRequest(info->pInfo->AuthType).ToString()); - - // Close the original - UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(info->pInfo->AccessToken); - - return new WindowsPrincipal(identity); - } - } - - return new WindowsPrincipal(WindowsIdentity.GetAnonymous()); // Anonymous / !IsAuthenticated - } - - private static AuthenticationSchemes GetAuthTypeFromRequest(HttpApi.HTTP_REQUEST_AUTH_TYPE input) - { - switch (input) - { - case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic: - return AuthenticationSchemes.Basic; - // case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest: - // return AuthenticationSchemes.Digest; - case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM: - return AuthenticationSchemes.NTLM; - case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate: - return AuthenticationSchemes.Negotiate; - case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos: - return AuthenticationSchemes.Kerberos; - default: - throw new NotImplementedException(input.ToString()); - } - } - - // These methods are for accessing the request structure after it has been unpinned. They need to adjust addresses - // in case GC has moved the original object. - - internal string GetKnownHeader(HttpSysRequestHeader header) - { - fixed (byte* pMemoryBlob = _backingBuffer) - { - var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); - long fixup = pMemoryBlob - (byte*)_originalBufferAddress; - int headerIndex = (int)header; - string value = null; - - HttpApi.HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; - // For known headers, when header value is empty, RawValueLength will be 0 and - // pRawValue will point to empty string ("\0") - if (pKnownHeader->pRawValue != null) - { - value = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength); - } - - return value; - } - } - - internal void GetUnknownHeaders(IDictionary unknownHeaders) - { - // Return value. - fixed (byte* pMemoryBlob = _backingBuffer) - { - var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); - long fixup = pMemoryBlob - (byte*)_originalBufferAddress; - int index; - - // unknown headers - if (request->Headers.UnknownHeaderCount != 0) - { - var pUnknownHeader = (HttpApi.HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders); - for (index = 0; index < request->Headers.UnknownHeaderCount; index++) - { - // For unknown headers, when header value is empty, RawValueLength will be 0 and - // pRawValue will be null. - if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0) - { - var headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength); - string headerValue; - if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) - { - headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength); - } - else - { - headerValue = string.Empty; - } - // Note that Http.Sys currently collapses all headers of the same name to a single coma separated string, - // so we can just call Set. - unknownHeaders[headerName] = headerValue; - } - pUnknownHeader++; - } - } - } - } - - internal SocketAddress GetRemoteEndPoint() - { - return GetEndPoint(localEndpoint: false); - } - - internal SocketAddress GetLocalEndPoint() - { - return GetEndPoint(localEndpoint: true); - } - - private SocketAddress GetEndPoint(bool localEndpoint) - { - fixed (byte* pMemoryBlob = _backingBuffer) - { - var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); - var source = localEndpoint ? (byte*)request->Address.pLocalAddress : (byte*)request->Address.pRemoteAddress; - - if (source == null) - { - return null; - } - var address = (IntPtr)(pMemoryBlob + _bufferAlignment - (byte*)_originalBufferAddress + source); - return CopyOutAddress(address); - } - } - - private static SocketAddress CopyOutAddress(IntPtr address) - { - ushort addressFamily = *((ushort*)address); - if (addressFamily == (ushort)AddressFamily.InterNetwork) - { - var v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize); - fixed (byte* pBuffer = v4address.Buffer) - { - for (int index = 2; index < SocketAddress.IPv4AddressSize; index++) - { - pBuffer[index] = ((byte*)address)[index]; - } - } - return v4address; - } - if (addressFamily == (ushort)AddressFamily.InterNetworkV6) - { - var v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize); - fixed (byte* pBuffer = v6address.Buffer) - { - for (int index = 2; index < SocketAddress.IPv6AddressSize; index++) - { - pBuffer[index] = ((byte*)address)[index]; - } - } - return v6address; - } - - return null; - } - - internal uint GetChunks(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) - { - // Return value. - uint dataRead = 0; - fixed (byte* pMemoryBlob = _backingBuffer) - { - var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment); - long fixup = pMemoryBlob - (byte*)_originalBufferAddress; - - if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) - { - var pDataChunk = (HttpApi.HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); - - fixed (byte* pReadBuffer = buffer) - { - byte* pTo = &pReadBuffer[offset]; - - while (dataChunkIndex < request->EntityChunkCount && dataRead < size) - { - if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength) - { - dataChunkOffset = 0; - dataChunkIndex++; - pDataChunk++; - } - else - { - byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup; - - uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset; - if (bytesToRead > (uint)size) - { - bytesToRead = (uint)size; - } - for (uint i = 0; i < bytesToRead; i++) - { - *(pTo++) = *(pFrom++); - } - dataRead += bytesToRead; - dataChunkOffset += bytesToRead; - } - } - } - } - // we're finished. - if (dataChunkIndex == request->EntityChunkCount) - { - dataChunkIndex = -1; - } - } - - return dataRead; - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 7e4ef322d6..3dedf347a9 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -5,11 +5,11 @@ using System; using System.Globalization; using System.IO; using System.Net; -using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -27,8 +27,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys private long? _contentLength; private RequestStream _nativeStream; - private SocketAddress _localEndPoint; - private SocketAddress _remoteEndPoint; + private AspNetCore.HttpSys.Internal.SocketAddress _localEndPoint; + private AspNetCore.HttpSys.Internal.SocketAddress _remoteEndPoint; private bool _isDisposed = false; @@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var originalPath = RequestUriBuilder.DecodeAndUnescapePath(rawUrlInBytes); // 'OPTIONS * HTTP/1.1' - if (KnownMethod == HttpApi.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal)) + if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal)) { PathBase = string.Empty; Path = string.Empty; @@ -79,9 +79,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys ProtocolVersion = _nativeRequestContext.GetVersion(); - Headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext)); + Headers = new RequestHeaders(_nativeRequestContext); - User = nativeRequestContext.GetUser(); + User = _nativeRequestContext.GetUser(); // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/HttpSysServer/issues/231 @@ -136,11 +136,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - public HeaderCollection Headers { get; } + public RequestHeaders Headers { get; } - internal HttpApi.HTTP_VERB KnownMethod { get; } + internal HttpApiTypes.HTTP_VERB KnownMethod { get; } - internal bool IsHeadMethod => KnownMethod == HttpApi.HTTP_VERB.HttpVerbHEAD; + internal bool IsHeadMethod => KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbHEAD; public string Method { get; } @@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - private SocketAddress RemoteEndPoint + private AspNetCore.HttpSys.Internal.SocketAddress RemoteEndPoint { get { @@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - private SocketAddress LocalEndPoint + private AspNetCore.HttpSys.Internal.SocketAddress LocalEndPoint { get { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index a57064fb55..89405cf538 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -10,6 +10,7 @@ using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index baef4c5a9f..284a3d856e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -7,6 +7,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.HttpSys diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs index 5304f616f1..a2fa887f56 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs @@ -7,6 +7,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index 427f1a1f2b..feef66ca24 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -10,8 +10,9 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Primitives; -using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods; +using static Microsoft.AspNetCore.HttpSys.Internal.UnsafeNclNativeMethods; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -24,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private TimeSpan? _cacheTtl; private long _expectedBodyLength; private BoundaryType _boundaryType; - private HttpApi.HTTP_RESPONSE_V2 _nativeResponse; + private HttpApiTypes.HTTP_RESPONSE_V2 _nativeResponse; internal Response(RequestContext requestContext) { @@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Headers = new HeaderCollection(); // We haven't started yet, or we're just buffered, we can clear any data, headers, and state so // that we can start over (e.g. to write an error message). - _nativeResponse = new HttpApi.HTTP_RESPONSE_V2(); + _nativeResponse = new HttpApiTypes.HTTP_RESPONSE_V2(); Headers.IsReadOnly = false; Headers.Clear(); _reasonPhrase = null; @@ -249,9 +250,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys // What would we loose by bypassing HttpSendHttpResponse? // // TODO: Consider using the HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA flag for most/all responses rather than just Opaque. - internal unsafe uint SendHeaders(HttpApi.HTTP_DATA_CHUNK[] dataChunks, + internal unsafe uint SendHeaders(HttpApiTypes.HTTP_DATA_CHUNK[] dataChunks, ResponseStreamAsyncResult asyncResult, - HttpApi.HTTP_FLAGS flags, + HttpApiTypes.HTTP_FLAGS flags, bool isOpaqueUpgrade) { Debug.Assert(!HasStarted, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); @@ -273,7 +274,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var handle = GCHandle.Alloc(dataChunks, GCHandleType.Pinned); pinnedHeaders.Add(handle); _nativeResponse.Response_V1.EntityChunkCount = (ushort)dataChunks.Length; - _nativeResponse.Response_V1.pEntityChunks = (HttpApi.HTTP_DATA_CHUNK*)handle.AddrOfPinnedObject(); + _nativeResponse.Response_V1.pEntityChunks = (HttpApiTypes.HTTP_DATA_CHUNK*)handle.AddrOfPinnedObject(); } else if (asyncResult != null && asyncResult.DataChunks != null) { @@ -286,10 +287,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys _nativeResponse.Response_V1.pEntityChunks = null; } - var cachePolicy = new HttpApi.HTTP_CACHE_POLICY(); + var cachePolicy = new HttpApiTypes.HTTP_CACHE_POLICY(); if (_cacheTtl.HasValue && _cacheTtl.Value > TimeSpan.Zero) { - cachePolicy.Policy = HttpApi.HTTP_CACHE_POLICY_TYPE.HttpCachePolicyTimeToLive; + cachePolicy.Policy = HttpApiTypes.HTTP_CACHE_POLICY_TYPE.HttpCachePolicyTimeToLive; cachePolicy.SecondsToLive = (uint)Math.Min(_cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue); } @@ -297,8 +298,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys fixed (byte* pReasonPhrase = reasonPhraseBytes) { _nativeResponse.Response_V1.ReasonLength = (ushort)reasonPhraseBytes.Length; - _nativeResponse.Response_V1.pReason = (sbyte*)pReasonPhrase; - fixed (HttpApi.HTTP_RESPONSE_V2* pResponse = &_nativeResponse) + _nativeResponse.Response_V1.pReason = (byte*)pReasonPhrase; + fixed (HttpApiTypes.HTTP_RESPONSE_V2* pResponse = &_nativeResponse) { statusCode = HttpApi.HttpSendHttpResponse( @@ -330,14 +331,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys return statusCode; } - internal HttpApi.HTTP_FLAGS ComputeHeaders(long writeCount, bool endOfRequest = false) + internal HttpApiTypes.HTTP_FLAGS ComputeHeaders(long writeCount, bool endOfRequest = false) { if (StatusCode == (ushort)StatusCodes.Status401Unauthorized) { RequestContext.Server.Options.Authentication.SetAuthenticationChallenge(RequestContext); } - var flags = HttpApi.HTTP_FLAGS.NONE; + var flags = HttpApiTypes.HTTP_FLAGS.NONE; Debug.Assert(!HasComputedHeaders, nameof(HasComputedHeaders) + " is true."); _responseState = ResponseState.ComputedHeaders; @@ -414,7 +415,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { Headers.Append(HttpKnownHeaderNames.Connection, Constants.Close); } - flags = HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; + flags = HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } return flags; @@ -428,8 +429,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys private unsafe List SerializeHeaders(bool isOpaqueUpgrade) { Headers.IsReadOnly = true; // Prohibit further modifications. - HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; - HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; + HttpApiTypes.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; + HttpApiTypes.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; List pinnedHeaders; GCHandle gcHandle; @@ -452,11 +453,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys continue; } // See if this is an unknown header - lookup = HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); + lookup = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. if (lookup == -1 || - (isOpaqueUpgrade && lookup == (int)HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) + (isOpaqueUpgrade && lookup == (int)HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { numUnknownHeaders += headerPair.Value.Count; } @@ -469,7 +470,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys try { - fixed (HttpApi.HTTP_KNOWN_HEADER* pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders) + fixed (HttpApiTypes.HTTP_KNOWN_HEADER* pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders) { foreach (var headerPair in Headers) { @@ -479,18 +480,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys } headerName = headerPair.Key; StringValues headerValues = headerPair.Value; - lookup = HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); + lookup = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. if (lookup == -1 || - (isOpaqueUpgrade && lookup == (int)HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) + (isOpaqueUpgrade && lookup == (int)HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { if (unknownHeaders == null) { - unknownHeaders = new HttpApi.HTTP_UNKNOWN_HEADER[numUnknownHeaders]; + unknownHeaders = new HttpApiTypes.HTTP_UNKNOWN_HEADER[numUnknownHeaders]; gcHandle = GCHandle.Alloc(unknownHeaders, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - _nativeResponse.Response_V1.Headers.pUnknownHeaders = (HttpApi.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + _nativeResponse.Response_V1.Headers.pUnknownHeaders = (HttpApiTypes.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); } for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) @@ -500,7 +501,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].NameLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pName = (sbyte*)gcHandle.AddrOfPinnedObject(); + unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pName = (byte*)gcHandle.AddrOfPinnedObject(); // Add Value headerValue = headerValues[headerValueIndex] ?? string.Empty; @@ -508,7 +509,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pRawValue = (byte*)gcHandle.AddrOfPinnedObject(); _nativeResponse.Response_V1.Headers.UnknownHeaderCount++; } } @@ -519,30 +520,30 @@ namespace Microsoft.AspNetCore.Server.HttpSys pKnownHeaders[lookup].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - pKnownHeaders[lookup].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + pKnownHeaders[lookup].pRawValue = (byte*)gcHandle.AddrOfPinnedObject(); } else { if (knownHeaderInfo == null) { - knownHeaderInfo = new HttpApi.HTTP_RESPONSE_INFO[numKnownMultiHeaders]; + knownHeaderInfo = new HttpApiTypes.HTTP_RESPONSE_INFO[numKnownMultiHeaders]; gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - _nativeResponse.pResponseInfo = (HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); + _nativeResponse.pResponseInfo = (HttpApiTypes.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject(); } - knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; - knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf(); + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = HttpApiTypes.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf(); - HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS(); + HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS(); - header.HeaderId = (HttpApi.HTTP_RESPONSE_HEADER_ID.Enum)lookup; - header.Flags = HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only. + header.HeaderId = (HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum)lookup; + header.Flags = HttpApiTypes.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only. - HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApi.HTTP_KNOWN_HEADER[headerValues.Count]; + HttpApiTypes.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApiTypes.HTTP_KNOWN_HEADER[headerValues.Count]; gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - header.KnownHeaders = (HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); + header.KnownHeaders = (HttpApiTypes.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject(); for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { @@ -552,14 +553,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - nativeHeaderValues[header.KnownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject(); + nativeHeaderValues[header.KnownHeaderCount].pRawValue = (byte*)gcHandle.AddrOfPinnedObject(); header.KnownHeaderCount++; } // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); - knownHeaderInfo[_nativeResponse.ResponseInfoCount].pInfo = (HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); + knownHeaderInfo[_nativeResponse.ResponseInfoCount].pInfo = (HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject(); _nativeResponse.ResponseInfoCount++; } @@ -595,9 +596,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys // TODO: Send headers async? ulong errorCode = SendHeaders(null, null, - HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE | - HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA | - HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA, + HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE | + HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA | + HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA, true); if (errorCode != ErrorCodes.ERROR_SUCCESS) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs index 35eb89c6e7..87ae976cbd 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs @@ -9,8 +9,9 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.Extensions.Logging; -using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods; +using static Microsoft.AspNetCore.HttpSys.Internal.UnsafeNclNativeMethods; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } uint statusCode = 0; - HttpApi.HTTP_DATA_CHUNK[] dataChunks; + HttpApiTypes.HTTP_DATA_CHUNK[] dataChunks; var pinnedBuffers = PinDataBuffers(endOfRequest, data, out dataChunks); try { @@ -142,7 +143,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } else { - fixed (HttpApi.HTTP_DATA_CHUNK* pDataChunks = dataChunks) + fixed (HttpApiTypes.HTTP_DATA_CHUNK* pDataChunks = dataChunks) { statusCode = HttpApi.HttpSendResponseEntityBody( RequestQueueHandle, @@ -183,7 +184,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - private List PinDataBuffers(bool endOfRequest, ArraySegment data, out HttpApi.HTTP_DATA_CHUNK[] dataChunks) + private List PinDataBuffers(bool endOfRequest, ArraySegment data, out HttpApiTypes.HTTP_DATA_CHUNK[] dataChunks) { var pins = new List(); var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked; @@ -192,14 +193,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys // Figure out how many data chunks if (chunked && data.Count == 0 && endOfRequest) { - dataChunks = new HttpApi.HTTP_DATA_CHUNK[1]; + dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[1]; SetDataChunk(dataChunks, ref currentChunk, pins, new ArraySegment(Helpers.ChunkTerminator)); return pins; } else if (data.Count == 0) { // No data - dataChunks = new HttpApi.HTTP_DATA_CHUNK[0]; + dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[0]; return pins; } @@ -215,7 +216,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys chunkCount += 1; } } - dataChunks = new HttpApi.HTTP_DATA_CHUNK[chunkCount]; + dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[chunkCount]; if (chunked) { @@ -238,11 +239,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys return pins; } - private static void SetDataChunk(HttpApi.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, List pins, ArraySegment buffer) + private static void SetDataChunk(HttpApiTypes.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, List pins, ArraySegment buffer) { var handle = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); pins.Add(handle); - chunks[chunkIndex].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + chunks[chunkIndex].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; chunks[chunkIndex].fromMemory.pBuffer = handle.AddrOfPinnedObject() + buffer.Offset; chunks[chunkIndex].fromMemory.BufferLength = (uint)buffer.Count; chunkIndex++; @@ -355,7 +356,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } // Last write, cache it for special cancellation handling. - if ((flags & HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) + if ((flags & HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) { _lastWrite = asyncResult; } @@ -405,9 +406,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys _requestContext.Abort(); } - private HttpApi.HTTP_FLAGS ComputeLeftToWrite(long writeCount, bool endOfRequest = false) + private HttpApiTypes.HTTP_FLAGS ComputeLeftToWrite(long writeCount, bool endOfRequest = false) { - var flags = HttpApi.HTTP_FLAGS.NONE; + var flags = HttpApiTypes.HTTP_FLAGS.NONE; if (!_requestContext.Response.HasComputedHeaders) { flags = _requestContext.Response.ComputeHeaders(writeCount, endOfRequest); @@ -430,11 +431,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (endOfRequest && _requestContext.Response.BoundaryType == BoundaryType.Close) { - flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; + flags |= HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } else if (!endOfRequest && _leftToWrite != writeCount) { - flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; + flags |= HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; } // Update _leftToWrite now so we can queue up additional async writes. @@ -647,7 +648,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } // Last write, cache it for special cancellation handling. - if ((flags & HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) + if ((flags & HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) { _lastWrite = asyncResult; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs index 28a890e51a..32a90e4b51 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs @@ -7,7 +7,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(Callback); private SafeNativeOverlapped _overlapped; - private HttpApi.HTTP_DATA_CHUNK[] _dataChunks; + private HttpApiTypes.HTTP_DATA_CHUNK[] _dataChunks; private FileStream _fileStream; private ResponseBody _responseStream; private TaskCompletionSource _tcs; @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys return; } - _dataChunks = new HttpApi.HTTP_DATA_CHUNK[1 + (chunked ? 2 : 0)]; + _dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[1 + (chunked ? 2 : 0)]; objectsToPin = new object[_dataChunks.Length + 1]; objectsToPin[0] = _dataChunks; var currentChunk = 0; @@ -110,7 +110,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } else { - _dataChunks = new HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1]; + _dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[chunked ? 3 : 1]; object[] objectsToPin = new object[_dataChunks.Length]; objectsToPin[_dataChunks.Length - 1] = _dataChunks; @@ -119,23 +119,23 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (chunked) { chunkHeaderBuffer = Helpers.GetChunkHeader(count); - _dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[0].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; _dataChunks[0].fromMemory.BufferLength = (uint)chunkHeaderBuffer.Count; objectsToPin[0] = chunkHeaderBuffer.Array; - _dataChunks[1].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; + _dataChunks[1].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[1].fromFile.offset = (ulong)offset; _dataChunks[1].fromFile.count = (ulong)count; _dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); // Nothing to pin for the file handle. - _dataChunks[2].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + _dataChunks[2].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; _dataChunks[2].fromMemory.BufferLength = (uint)Helpers.CRLF.Length; objectsToPin[1] = Helpers.CRLF; } else { - _dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; + _dataChunks[0].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle; _dataChunks[0].fromFile.offset = (ulong)offset; _dataChunks[0].fromFile.count = (ulong)count; _dataChunks[0].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle(); @@ -154,11 +154,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - private static void SetDataChunk(HttpApi.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, object[] objectsToPin, ref int pinIndex, ArraySegment segment) + private static void SetDataChunk(HttpApiTypes.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, object[] objectsToPin, ref int pinIndex, ArraySegment segment) { objectsToPin[pinIndex] = segment.Array; pinIndex++; - chunks[chunkIndex].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; + chunks[chunkIndex].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; // The address is not set until after we pin it with Overlapped chunks[chunkIndex].fromMemory.BufferLength = (uint)segment.Count; chunkIndex++; @@ -195,7 +195,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - internal HttpApi.HTTP_DATA_CHUNK* DataChunks + internal HttpApiTypes.HTTP_DATA_CHUNK* DataChunks { get { @@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } else { - return (HttpApi.HTTP_DATA_CHUNK*)(Marshal.UnsafeAddrOfPinnedArrayElement(_dataChunks, 0)); + return (HttpApiTypes.HTTP_DATA_CHUNK*)(Marshal.UnsafeAddrOfPinnedArrayElement(_dataChunks, 0)); } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs b/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs index aa61ef85a4..e9bb62dfce 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.InteropServices; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public sealed class TimeoutManager { private static readonly int TimeoutLimitSize = - Marshal.SizeOf(); + Marshal.SizeOf(); private UrlGroup _urlGroup; private int[] _timeouts; @@ -47,11 +48,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys { get { - return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.EntityBody); + return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.EntityBody); } set { - SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value); + SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.EntityBody, value); } } @@ -70,11 +71,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys { get { - return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody); + return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.DrainEntityBody); } set { - SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value); + SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.DrainEntityBody, value); } } @@ -88,11 +89,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys { get { - return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue); + return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.RequestQueue); } set { - SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value); + SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.RequestQueue, value); } } @@ -107,11 +108,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys { get { - return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection); + return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.IdleConnection); } set { - SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value); + SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.IdleConnection, value); } } @@ -127,11 +128,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys { get { - return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait); + return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.HeaderWait); } set { - SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value); + SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.HeaderWait, value); } } @@ -167,13 +168,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys #region Helpers - private TimeSpan GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE type) + private TimeSpan GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE type) { // Since we maintain local state, GET is local. return new TimeSpan(0, 0, (int)_timeouts[(int)type]); } - private void SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value) + private void SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE type, TimeSpan value) { // All timeouts are defined as USHORT in native layer (except MinSendRate, which is ULONG). Make sure that // timeout value is within range. @@ -207,25 +208,25 @@ namespace Microsoft.AspNetCore.Server.HttpSys return; } - var timeoutinfo = new HttpApi.HTTP_TIMEOUT_LIMIT_INFO(); + var timeoutinfo = new HttpApiTypes.HTTP_TIMEOUT_LIMIT_INFO(); - timeoutinfo.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + timeoutinfo.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; timeoutinfo.DrainEntityBody = - (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody]; + (ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.DrainEntityBody]; timeoutinfo.EntityBody = - (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.EntityBody]; + (ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.EntityBody]; timeoutinfo.RequestQueue = - (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue]; + (ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.RequestQueue]; timeoutinfo.IdleConnection = - (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection]; + (ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.IdleConnection]; timeoutinfo.HeaderWait = - (ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait]; + (ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.HeaderWait]; timeoutinfo.MinSendRate = minSendBytesPerSecond; var infoptr = new IntPtr(&timeoutinfo); _urlGroup.SetProperty( - HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty, + HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty, infoptr, (uint)TimeoutLimitSize); } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs b/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs index 1a74402a9f..4286870d71 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs @@ -3,6 +3,7 @@ using System; using System.Globalization; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs index 7232d97fe4..5fc93e69e7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs index 56f8989859..38ec6d0cb2 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.HttpSys.Internal; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; From 69b44bb3773cc1d9f561f6849b1708377ba14157 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 5 Oct 2017 17:37:14 -0700 Subject: [PATCH 533/597] Minor test code change to resolve xUnit2013 build error --- .../RequestHeaderTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs index 7491df91bd..39e237eb5e 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs @@ -45,9 +45,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.False(StringValues.IsNullOrEmpty(requestHeaders["Host"])); Assert.Equal("close", requestHeaders["Connection"]); // Apparently Http.Sys squashes request headers together. - Assert.Equal(1, requestHeaders["Custom-Header"].Count); + Assert.Single(requestHeaders["Custom-Header"]); Assert.Equal("custom1, and custom2, custom3", requestHeaders["Custom-Header"]); - Assert.Equal(1, requestHeaders["Spacer-Header"].Count); + Assert.Single(requestHeaders["Spacer-Header"]); Assert.Equal("spacervalue, spacervalue", requestHeaders["Spacer-Header"]); return Task.FromResult(0); })) From 6ee0186c36e325b97143816026a936670b3f2d14 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 20 Sep 2017 13:20:43 -0700 Subject: [PATCH 534/597] Update bootstrappers --- .appveyor.yml | 4 +- build.cmd | 2 +- build.sh | 197 +------------------------------------- run.cmd | 2 + build.ps1 => run.ps1 | 56 +++++++---- run.sh | 223 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 266 insertions(+), 218 deletions(-) create mode 100644 run.cmd rename build.ps1 => run.ps1 (73%) create mode 100755 run.sh diff --git a/.appveyor.yml b/.appveyor.yml index 31efd8196f..46038786c9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -init: +init: - git config --global core.autocrlf true branches: only: @@ -7,7 +7,7 @@ branches: - dev - /^(.*\/)?ci-.*$/ build_script: - - ps: .\build.ps1 + - ps: .\run.ps1 default-build clone_depth: 1 environment: global: diff --git a/build.cmd b/build.cmd index b6c8d24864..c0050bda12 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.sh b/build.sh index 11cdbe5504..98a4b22765 100755 --- a/build.sh +++ b/build.sh @@ -1,199 +1,8 @@ #!/usr/bin/env bash set -euo pipefail - -# -# variables -# - -RESET="\033[0m" -RED="\033[0;31m" -MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" -config_file="$DIR/version.xml" -verbose=false -update=false -repo_path="$DIR" -channel='' -tools_source='' -# -# Functions -# -__usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...]" - echo "" - echo "Arguments:" - echo " ... Arguments passed to MSBuild. Variable number of arguments allowed." - echo "" - echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file TThe path to the configuration file that stores values. Defaults to version.xml." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source The base url where build tools can be downloaded. Overrides the value from the config file." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." - echo "" - echo "Description:" - echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." - echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - - if [[ "${1:-}" != '--no-exit' ]]; then - exit 2 - fi -} - -get_korebuild() { - local version - local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" - fi - version="$(grep 'version:*' -m 1 "$lock_file")" - if [[ "$version" == '' ]]; then - __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" - return 1 - fi - version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" - - { - if [ ! -d "$korebuild_path" ]; then - mkdir -p "$korebuild_path" - local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" - tmpfile="$(mktemp)" - echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile"; then - unzip -q -d "$korebuild_path" "$tmpfile" - fi - rm "$tmpfile" || true - fi - - source "$korebuild_path/KoreBuild.sh" - } || { - if [ -d "$korebuild_path" ]; then - echo "Cleaning up after failed installation" - rm -rf "$korebuild_path" || true - fi - return 1 - } -} - -__error() { - echo -e "${RED}$*${RESET}" 1>&2 -} - -__machine_has() { - hash "$1" > /dev/null 2>&1 - return $? -} - -__get_remote_file() { - local remote_path=$1 - local local_path=$2 - - if [[ "$remote_path" != 'http'* ]]; then - cp "$remote_path" "$local_path" - return 0 - fi - - local failed=false - if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true - else - failed=true - fi - - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true - fi - - if [ "$failed" = true ]; then - __error "Download failed: $remote_path" 1>&2 - return 1 - fi -} - -__read_dom () { local IFS=\> ; read -r -d \< ENTITY CONTENT ;} - -# -# main -# - -while [[ $# -gt 0 ]]; do - case $1 in - -\?|-h|--help) - __usage --no-exit - exit 0 - ;; - -c|--channel|-Channel) - shift - channel="${1:-}" - [ -z "$channel" ] && __usage - ;; - --config-file|-ConfigFile) - shift - config_file="${1:-}" - [ -z "$config_file" ] && __usage - ;; - -d|--dotnet-home|-DotNetHome) - shift - DOTNET_HOME="${1:-}" - [ -z "$DOTNET_HOME" ] && __usage - ;; - --path|-Path) - shift - repo_path="${1:-}" - [ -z "$repo_path" ] && __usage - ;; - -s|--tools-source|-ToolsSource) - shift - tools_source="${1:-}" - [ -z "$tools_source" ] && __usage - ;; - -u|--update|-Update) - update=true - ;; - --verbose|-Verbose) - verbose=true - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -if ! __machine_has unzip; then - __error 'Missing required command: unzip' - exit 1 -fi - -if ! __machine_has curl && ! __machine_has wget; then - __error 'Missing required command. Either wget or curl is required.' - exit 1 -fi - -if [ -f "$config_file" ]; then - comment=false - while __read_dom; do - if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi - if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi - if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi - if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi - done < "$config_file" -fi - -[ -z "$channel" ] && channel='dev' -[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' - -get_korebuild -install_tools "$tools_source" "$DOTNET_HOME" -invoke_repository_build "$repo_path" "$@" +# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) +chmod +x "$DIR/run.sh"; sync +"$DIR/run.sh" default-build "$@" diff --git a/run.cmd b/run.cmd new file mode 100644 index 0000000000..d52d5c7e68 --- /dev/null +++ b/run.cmd @@ -0,0 +1,2 @@ +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/run.ps1 similarity index 73% rename from build.ps1 rename to run.ps1 index d5eb4d5cf2..49c2899856 100644 --- a/build.ps1 +++ b/run.ps1 @@ -3,10 +3,13 @@ <# .SYNOPSIS -Build this repository +Executes KoreBuild commands. .DESCRIPTION -Downloads korebuild if required. Then builds the repository. +Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. + +.PARAMETER Command +The KoreBuild command to run. .PARAMETER Path The folder to build. Defaults to the folder containing this script. @@ -24,31 +27,32 @@ The base url where build tools can be downloaded. Overrides the value from the c Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile -The path to the configuration file that stores values. Defaults to version.xml. +The path to the configuration file that stores values. Defaults to korebuild.json. -.PARAMETER MSBuildArgs -Arguments to be passed to MSBuild +.PARAMETER Arguments +Arguments to be passed to the command .NOTES This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. -The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well. +The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set +in the file are overridden by command line parameters. .EXAMPLE Example config file: -```xml - - - - dev - https://aspnetcore.blob.core.windows.net/buildtools - - +```json +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", + "channel": "dev", + "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" +} ``` #> [CmdletBinding(PositionalBinding = $false)] param( + [Parameter(Mandatory=$true, Position = 0)] + [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] [string]$Channel, @@ -58,9 +62,9 @@ param( [string]$ToolsSource, [Alias('u')] [switch]$Update, - [string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'), + [string]$ConfigFile, [Parameter(ValueFromRemainingArguments = $true)] - [string[]]$MSBuildArgs + [string[]]$Arguments ) Set-StrictMode -Version 2 @@ -147,10 +151,20 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { # Load configuration or set defaults +$Path = Resolve-Path $Path +if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } + if (Test-Path $ConfigFile) { - [xml] $config = Get-Content $ConfigFile - if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' } - if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' } + try { + $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json + if ($config) { + if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } + if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} + } + } catch { + Write-Warning "$ConfigFile could not be read. Its settings will be ignored." + Write-Warning $Error[0] + } } if (!$DotNetHome) { @@ -169,8 +183,8 @@ $korebuildPath = Get-KoreBuild Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') try { - Install-Tools $ToolsSource $DotNetHome - Invoke-RepositoryBuild $Path @MSBuildArgs + Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile + Invoke-KoreBuildCommand $Command @Arguments } finally { Remove-Module 'KoreBuild' -ErrorAction Ignore diff --git a/run.sh b/run.sh new file mode 100755 index 0000000000..c278423acc --- /dev/null +++ b/run.sh @@ -0,0 +1,223 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# +# variables +# + +RESET="\033[0m" +RED="\033[0;31m" +YELLOW="\033[0;33m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" +verbose=false +update=false +repo_path="$DIR" +channel='' +tools_source='' + +# +# Functions +# +__usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " command The command to be run." + echo " ... Arguments passed to the command. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." + + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 + fi +} + +get_korebuild() { + local version + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" + fi + version="$(grep 'version:*' -m 1 "$lock_file")" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file "$remote_path" "$tmpfile"; then + unzip -q -d "$korebuild_path" "$tmpfile" + fi + rm "$tmpfile" || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}error: $*${RESET}" 1>&2 +} + +__warn() { + echo -e "${YELLOW}warning: $*${RESET}" +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + + if [[ "$remote_path" != 'http'* ]]; then + cp "$remote_path" "$local_path" + return 0 + fi + + local failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + else + failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +# +# main +# + +command="${1:-}" +shift + +while [[ $# -gt 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel="${1:-}" + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + if [ ! -f "$config_file" ]; then + __error "Invalid value for --config-file. $config_file does not exist." + exit 1 + fi + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME="${1:-}" + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 +fi + +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" +if [ -f "$config_file" ]; then + if __machine_has jq ; then + if jq '.' "$config_file" >/dev/null ; then + config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" + config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" + else + __warn "$config_file is invalid JSON. Its settings will be ignored." + fi + elif __machine_has python ; then + if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then + config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" + config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" + else + __warn "$config_file is invalid JSON. Its settings will be ignored." + fi + else + __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' + fi + + [ ! -z "${config_channel:-}" ] && channel="$config_channel" + [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" +fi + +[ -z "$channel" ] && channel='dev' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" +invoke_korebuild_command "$command" "$@" From 7f96eab775d721a3bf8d05be446086dab4b45aae Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Wed, 11 Oct 2017 15:31:00 -0700 Subject: [PATCH 535/597] #381 handle known headers with no value. --- .../RequestProcessing/NativeRequestContext.cs | 2 +- .../Listener/RequestHeaderTests.cs | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs index 45d002e5b8..a0985c87ce 100644 --- a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs @@ -259,7 +259,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal HttpApiTypes.HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex; // For known headers, when header value is empty, RawValueLength will be 0 and // pRawValue will point to empty string ("\0") - if (pKnownHeader->pRawValue != null) + if (pKnownHeader->RawValueLength > 0) { value = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs index a333179271..4197d4faf0 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using System.Net.Http; using System.Net.Sockets; using System.Text; @@ -93,6 +94,56 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } + [ConditionalFact] + public async Task RequestHeaders_ClientSendsKnownHeaderWithNoValue_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + string[] customValues = new string[] { "" }; + Task responseTask = SendRequestAsync(address, "If-None-Match", customValues); + + var context = await server.AcceptAsync(Utilities.DefaultTimeout); + var requestHeaders = context.Request.Headers; + Assert.Equal(3, requestHeaders.Count); + Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); + Assert.Equal(new[] { new Uri(address).Authority }, requestHeaders.GetValues("Host")); + Assert.Equal("close", requestHeaders["Connection"]); + Assert.Equal(new[] { "close" }, requestHeaders.GetValues("Connection")); + Assert.Equal(StringValues.Empty, requestHeaders["If-None-Match"]); + Assert.Empty(requestHeaders.GetValues("If-None-Match")); + Assert.Equal("spacervalue", requestHeaders["Spacer-Header"]); + context.Dispose(); + + await responseTask; + } + } + + [ConditionalFact] + public async Task RequestHeaders_ClientSendsUnknownHeaderWithNoValue_Success() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + string[] customValues = new string[] { "" }; + Task responseTask = SendRequestAsync(address, "Custom-Header", customValues); + + var context = await server.AcceptAsync(Utilities.DefaultTimeout); + var requestHeaders = context.Request.Headers; + Assert.Equal(4, requestHeaders.Count); + Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]); + Assert.Equal(new[] { new Uri(address).Authority }, requestHeaders.GetValues("Host")); + Assert.Equal("close", requestHeaders["Connection"]); + Assert.Equal(new[] { "close" }, requestHeaders.GetValues("Connection")); + Assert.Equal("", requestHeaders["Custom-Header"]); + Assert.Empty(requestHeaders.GetValues("Custom-Header")); + Assert.Equal("spacervalue", requestHeaders["Spacer-Header"]); + context.Dispose(); + + await responseTask; + } + } + private async Task SendRequestAsync(string uri) { using (HttpClient client = new HttpClient()) From 748afb1f65d361f964588a8e0d6540655d6068e9 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 16 Oct 2017 10:03:20 -0700 Subject: [PATCH 536/597] #270 Fix hang in SendFile tests --- .../Listener/ResponseSendFileTests.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index a24bd3d4ac..cf7bab0591 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -510,7 +510,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "Tests hanging: https://github.com/aspnet/HttpSysServer/issues/270")] + [ConditionalFact] public async Task ResponseSendFileExceptions_ClientDisconnectsBeforeSecondSend_SendThrows() { string address; @@ -524,10 +524,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers - await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + var sendFileTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); var response = await responseTask; response.EnsureSuccessStatusCode(); + // Drain data from the connection so that SendFileAsync can complete. + var bufferTask = response.Content.LoadIntoBufferAsync(); + + await sendFileTask; response.Dispose(); } @@ -544,7 +548,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "Tests hanging: https://github.com/aspnet/WebListener/issues/270")] + [ConditionalFact] public async Task ResponseSendFile_ClientDisconnectsBeforeSecondSend_SendCompletesSilently() { string address; @@ -557,10 +561,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers - await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); + var sendFileTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); var response = await responseTask; response.EnsureSuccessStatusCode(); + // Drain data from the connection so that SendFileAsync can complete. + var bufferTask = response.Content.LoadIntoBufferAsync(); + + await sendFileTask; response.Dispose(); } From d3398b3ccf805491a1ec141d1af22fa19cd716ed Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Oct 2017 12:49:57 -0700 Subject: [PATCH 537/597] Add RepositoryRoot --- Directory.Build.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index c0098b5168..14b6c5e098 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,10 +1,11 @@ - + Microsoft ASP.NET Core https://github.com/aspnet/HttpSysServer git + $(MSBuildThisFileDirectory) $(MSBuildThisFileDirectory)build\Key.snk true true From 99fc843cc5805bc734a0e18a3f8cb2d975bdffdb Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 23 Oct 2017 14:27:19 -0700 Subject: [PATCH 538/597] Re-enable skipped tests --- .../Listener/ResponseBodyTests.cs | 30 +++++++++---------- .../Listener/ResponseSendFileTests.cs | 8 ++--- .../Listener/Utilities.cs | 2 ++ .../ResponseCachingTests.cs | 2 +- .../ServerTests.cs | 5 +--- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index c41ef371a7..2ea7910a11 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -176,7 +176,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthNotEnoughWritten_Aborts() { string address; @@ -193,7 +193,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public async Task ResponseBody_WriteContentLengthTooMuchWritten_Throws() { string address; @@ -305,7 +305,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_FirstWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -370,7 +370,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_SecondWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -392,7 +392,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public async Task ResponseBody_SecondWriteAsyncWithCanceledCancellationToken_CancelsAndAborts() { string address; @@ -432,7 +432,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Throws(() => { // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 1000; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { context.Response.Body.Write(new byte[1000], 0, 1000); } @@ -464,7 +464,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener await Assert.ThrowsAsync(async () => { // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 1000; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { await context.Response.Body.WriteAsync(new byte[1000], 0, 1000); } @@ -492,7 +492,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener await Assert.ThrowsAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 100; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { context.Response.Body.Write(new byte[1000], 0, 1000); } @@ -515,7 +515,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener await Assert.ThrowsAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 100; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { await context.Response.Body.WriteAsync(new byte[1000], 0, 1000); } @@ -523,7 +523,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWrite_WriteThrows() { string address; @@ -548,7 +548,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Throws(() => { // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 100; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { context.Response.Body.Write(new byte[1000], 0, 1000); } @@ -557,7 +557,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public async Task ResponseBodyWriteExceptions_ClientDisconnectsBeforeSecondWriteAsync_WriteThrows() { string address; @@ -582,7 +582,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener await Assert.ThrowsAsync(async () => { // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 100; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { await context.Response.Body.WriteAsync(new byte[1000], 0, 1000); } @@ -614,7 +614,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 10; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { context.Response.Body.Write(new byte[1000], 0, 1000); } @@ -644,7 +644,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 10; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { await context.Response.Body.WriteAsync(new byte[1000], 0, 1000); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index cf7bab0591..f1c1f4ba26 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -474,7 +474,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener await Assert.ThrowsAsync(async () => { // It can take several tries before Send notices the disconnect. - for (int i = 0; i < 1000; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); } @@ -502,7 +502,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener await Assert.ThrowsAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Send notices the disconnect. - for (int i = 0; i < 100; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); } @@ -539,7 +539,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener await Assert.ThrowsAsync(async () => { // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 100; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); } @@ -574,7 +574,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. - for (int i = 0; i < 10; i++) + for (int i = 0; i < Utilities.WriteRetryLimit; i++) { await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs index db41469119..b3fb1b1c8c 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs @@ -10,6 +10,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener { internal static class Utilities { + internal static readonly int WriteRetryLimit = 1000; + // When tests projects are run in parallel, overlapping port ranges can cause a race condition when looking for free // ports during dynamic port allocation. private const int BasePort = 8001; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs index 8fa4448c26..6a2fe8c57d 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public async Task Caching_MaxAge_Cached() { var requestCount = 1; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 22d53e02f7..4a451bd110 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -9,12 +9,9 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing.xunit; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Xunit; namespace Microsoft.AspNetCore.Server.HttpSys @@ -153,7 +150,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalFact(Skip = "https://github.com/aspnet/HttpSysServer/issues/263")] + [ConditionalFact] public void Server_MultipleOutstandingSyncRequests_Success() { int requestLimit = 10; From 02331040a127954eadaa859777379af77f419183 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Mon, 30 Oct 2017 21:41:31 -0700 Subject: [PATCH 539/597] Dispose of the existing native context before creating a new one. --- src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs index efb191760e..b9c0b1c447 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs @@ -184,6 +184,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal void AllocateNativeRequest(uint? size = null, ulong requestId = 0) { + _nativeRequestContext?.Dispose(); //Debug.Assert(size != 0, "unexpected size"); // We can't reuse overlapped objects From db210af712e39b9e396e8f86826b0da42a3e5ee2 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 1 Nov 2017 14:42:41 -0700 Subject: [PATCH 540/597] Pin tool and package versions to make builds more repeatable Part of aspnet/Universe#575 --- .gitignore | 1 - Directory.Build.props | 6 +++--- Directory.Build.targets | 17 ++++----------- NuGet.config | 1 + build/dependencies.props | 21 +++++++++++++++++++ build/repo.props | 9 ++++---- korebuild-lock.txt | 2 ++ korebuild.json | 4 ++++ samples/HotAddSample/HotAddSample.csproj | 2 +- samples/SelfHostServer/SelfHostServer.csproj | 2 +- src/Directory.Build.props | 4 ++-- ...Microsoft.AspNetCore.Server.HttpSys.csproj | 10 ++++----- test/Directory.Build.props | 12 +++++------ ...Core.Server.HttpSys.FunctionalTests.csproj | 2 +- version.props | 10 +++++++++ version.xml | 8 ------- 16 files changed, 66 insertions(+), 45 deletions(-) create mode 100644 build/dependencies.props create mode 100644 korebuild-lock.txt create mode 100644 korebuild.json create mode 100644 version.props delete mode 100644 version.xml diff --git a/.gitignore b/.gitignore index 94caeb71e6..e062ff6d76 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,3 @@ project.lock.json .build/ .testPublish/ global.json -korebuild-lock.txt diff --git a/Directory.Build.props b/Directory.Build.props index 14b6c5e098..a4d5ebdcd0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,6 @@ - - + + + Microsoft ASP.NET Core @@ -9,7 +10,6 @@ $(MSBuildThisFileDirectory)build\Key.snk true true - $(VersionSuffix)-$(BuildNumber) true diff --git a/Directory.Build.targets b/Directory.Build.targets index bc118fd907..e83ff95e39 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,14 +1,5 @@ - - - - <_BootstrapperFile Condition=" $([MSBuild]::IsOSUnixLike()) ">build.sh - <_BootstrapperFile Condition="! $([MSBuild]::IsOSUnixLike()) ">build.cmd - <_BootstrapperError> - Package references have not been pinned. Run './$(_BootstrapperFile) /t:Pin'. - Also, you can run './$(_BootstrapperFile) /t:Restore' which will pin *and* restore packages. '$(_BootstrapperFile)' can be found in '$(MSBuildThisFileDirectory)'. - - - - - + + + $(MicrosoftNETCoreApp20PackageVersion) + diff --git a/NuGet.config b/NuGet.config index 20060c934e..4e8a1f6de1 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,6 +3,7 @@ + diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 0000000000..9bdf31e9da --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,21 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + 2.1.0-preview1-15549 + 2.1.0-preview1-27496 + 2.1.0-preview1-27496 + 2.1.0-preview1-27496 + 2.1.0-preview1-27496 + 2.0.0 + 2.1.0-preview1-27496 + 15.3.0 + 4.4.0 + 4.4.0 + 4.4.0 + 2.3.0 + 2.3.0 + + + diff --git a/build/repo.props b/build/repo.props index 13fe1c296a..b55e651b87 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,6 +1,7 @@  - - - - + + + Internal.AspNetCore.Universe.Lineup + https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json + diff --git a/korebuild-lock.txt b/korebuild-lock.txt new file mode 100644 index 0000000000..45463cc71e --- /dev/null +++ b/korebuild-lock.txt @@ -0,0 +1,2 @@ +version:2.1.0-preview1-15549 +commithash:f570e08585fec510dd60cd4bfe8795388b757a95 diff --git a/korebuild.json b/korebuild.json new file mode 100644 index 0000000000..bd5d51a51b --- /dev/null +++ b/korebuild.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", + "channel": "dev" +} diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index a44d7e2f0a..49d0e73463 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -11,6 +11,6 @@ - + diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index a44d7e2f0a..49d0e73463 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -11,6 +11,6 @@ - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 9d9a3de33a..4b89a431e7 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,7 +1,7 @@ - + - + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index 592368a043..9be8bad15e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -14,11 +14,11 @@ - - - - - + + + + + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 82ba457f18..c79812719a 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,11 +1,11 @@ - + - - - - - + + + + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index ee9812fa48..ed1c368913 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -10,7 +10,7 @@ - + diff --git a/version.props b/version.props new file mode 100644 index 0000000000..5c4a7c32d1 --- /dev/null +++ b/version.props @@ -0,0 +1,10 @@ + + + 2.1.0 + preview1 + $(VersionPrefix) + $(VersionPrefix)-$(VersionSuffix)-final + t000 + $(VersionSuffix)-$(BuildNumber) + + diff --git a/version.xml b/version.xml deleted file mode 100644 index 3c05022b7d..0000000000 --- a/version.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - dev - 2.1.0 - preview1 - - From 936f82874ab1e706c39d5940c97752c01ef1cbef Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 2 Nov 2017 19:34:12 -0700 Subject: [PATCH 541/597] Release pins before disposal (#412) --- src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs index b9c0b1c447..01e74c1990 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs @@ -184,6 +184,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal void AllocateNativeRequest(uint? size = null, ulong requestId = 0) { + _nativeRequestContext?.ReleasePins(); _nativeRequestContext?.Dispose(); //Debug.Assert(size != 0, "unexpected size"); From 58fb4f322e78330d0d8ac3b5b0d86763ca0ecc70 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 14 Nov 2017 10:07:10 -0800 Subject: [PATCH 542/597] Update samples and tests to target netcoreapp2.1 --- Directory.Build.props | 4 ++++ korebuild-lock.txt | 4 ++-- samples/HotAddSample/HotAddSample.csproj | 2 +- samples/SelfHostServer/SelfHostServer.csproj | 2 +- test/Directory.Build.props | 7 +++++++ .../Listener/ResponseBodyTests.cs | 6 +++--- .../Listener/ResponseHeaderTests.cs | 4 ++-- .../Listener/ResponseSendFileTests.cs | 4 ++-- .../Listener/ServerTests.cs | 2 +- ...rosoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj | 3 +-- .../ResponseHeaderTests.cs | 4 ++-- .../Microsoft.AspNetCore.Server.HttpSys.Tests.csproj | 3 +-- 12 files changed, 27 insertions(+), 18 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index a4d5ebdcd0..36f05acd3b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,4 +1,8 @@  + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 45463cc71e..95f4613014 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15549 -commithash:f570e08585fec510dd60cd4bfe8795388b757a95 +version:2.1.0-preview1-15567 +commithash:903e3104807b1bb8cddd28bdef205b1e2dc021d1 diff --git a/samples/HotAddSample/HotAddSample.csproj b/samples/HotAddSample/HotAddSample.csproj index 49d0e73463..caf6da74fe 100644 --- a/samples/HotAddSample/HotAddSample.csproj +++ b/samples/HotAddSample/HotAddSample.csproj @@ -1,7 +1,7 @@  - netcoreapp2.0;net461 + netcoreapp2.1;net461 Exe true diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/samples/SelfHostServer/SelfHostServer.csproj index 49d0e73463..caf6da74fe 100644 --- a/samples/SelfHostServer/SelfHostServer.csproj +++ b/samples/SelfHostServer/SelfHostServer.csproj @@ -1,7 +1,7 @@  - netcoreapp2.0;net461 + netcoreapp2.1;net461 Exe true diff --git a/test/Directory.Build.props b/test/Directory.Build.props index c79812719a..036af693c5 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,6 +1,13 @@ + + netcoreapp2.1 + $(DeveloperBuildTestTfms) + $(StandardTestTfms);netcoreapp2.0 + $(StandardTestTfms);net461 + + diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index 2ea7910a11..ef56e997cb 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Response.Headers["Content-lenGth"] = " 20 "; context.Dispose(); -#elif NETCOREAPP2_0 +#elif NETCOREAPP2_0 || NETCOREAPP2_1 #else #error Target framework needs to be updated #endif @@ -330,7 +330,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#elif NETCOREAPP2_0 +#elif NETCOREAPP2_0 || NETCOREAPP2_1 #else #error Target framework needs to be updated #endif @@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener writeTask = context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#elif NETCOREAPP2_0 +#elif NETCOREAPP2_0 || NETCOREAPP2_1 #else #error Target framework needs to be updated #endif diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs index 86b377e7e3..727dd69ec6 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs @@ -252,7 +252,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 || NETCOREAPP2_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #elif NET461 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -283,7 +283,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 || NETCOREAPP2_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #elif NET461 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index f1c1f4ba26..2a962c69f2 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -371,7 +371,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#elif NETCOREAPP2_0 +#elif NETCOREAPP2_0 || NETCOREAPP2_1 #else #error Target framework needs to be updated #endif @@ -403,7 +403,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener writeTask = context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token); Assert.True(writeTask.IsCanceled); context.Dispose(); -#elif NETCOREAPP2_0 +#elif NETCOREAPP2_0 || NETCOREAPP2_1 #else #error Target framework needs to be updated #endif diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index e12488f13e..60c95a94f1 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -188,7 +188,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener // HttpClient re-tries the request because it doesn't know if the request was received. context = await server.AcceptAsync(Utilities.DefaultTimeout); context.Abort(); -#elif NETCOREAPP2_0 +#elif NETCOREAPP2_0 || NETCOREAPP2_1 #else #error Target framework needs to be updated #endif diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj index ed1c368913..dd4dc97dbc 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs index bec341b50f..ec93832e18 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 || NETCOREAPP2_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["WWW-Authenticate"]); #elif NET461 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("WWW-Authenticate")); @@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(0, response.ContentLength); Assert.NotNull(response.Headers["Date"]); Assert.Equal("Microsoft-HTTPAPI/2.0", response.Headers["Server"]); -#if NETCOREAPP2_0 // WebHeaderCollection.GetValues() not available in CoreCLR. +#if NETCOREAPP2_0 || NETCOREAPP2_1 // WebHeaderCollection.GetValues() not available in CoreCLR. Assert.Equal("custom1, and custom2, custom3", response.Headers["Custom-Header1"]); #elif NET461 Assert.Equal(new string[] { "custom1, and custom2", "custom3" }, response.Headers.GetValues("Custom-Header1")); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj index 0429172ecd..5628726d51 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj +++ b/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0;net461 - netcoreapp2.0 + $(StandardTestTfms) From cfd974337da492149fd7bb55688286d8b603b64b Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Fri, 3 Nov 2017 09:45:45 -0700 Subject: [PATCH 543/597] Improved request error handling. --- .../AsyncAcceptContext.cs | 6 ++++++ src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs | 2 +- src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs index 01e74c1990..4c0cd86756 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys @@ -80,6 +81,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys complete = true; } } + catch (Exception) + { + server.SendError(asyncResult._nativeRequestContext.RequestId, StatusCodes.Status400BadRequest); + throw; + } finally { // The request has been handed to the user, which means this code can't reuse the blob. Reset it here. diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs index 2c70016e3f..a1ad7493d8 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs @@ -316,7 +316,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys return true; } - private unsafe void SendError(ulong requestId, int httpStatusCode, IList authChallenges) + internal unsafe void SendError(ulong requestId, int httpStatusCode, IList authChallenges = null) { HttpApiTypes.HTTP_RESPONSE_V2 httpResponse = new HttpApiTypes.HTTP_RESPONSE_V2(); httpResponse.Response_V1.Version = new HttpApiTypes.HTTP_VERSION(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 2b06066936..e70c52d89c 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { LogHelper.LogException(_logger, "ListenForNextRequestAsync", exception); } - return; + continue; } try { From 848e3c5cdaee7e4923c56914877ca56a1da11747 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Wed, 15 Nov 2017 14:05:21 -0800 Subject: [PATCH 544/597] Fix parsing error on raw urls without path. (#406) --- .../RequestProcessing/RawUrlHelper.cs | 6 +++- .../Listener/RequestTests.cs | 17 +++++++++ .../RequestTests.cs | 36 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs index 7402c4ef8f..ee0bf4a996 100644 --- a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs @@ -2,11 +2,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Text; namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class RawUrlHelper { + private static readonly byte[] _forwardSlashPath = Encoding.ASCII.GetBytes("/"); + /// /// Find the segment of the URI byte array which represents the path. /// @@ -39,7 +42,8 @@ namespace Microsoft.AspNetCore.HttpSys.Internal if (pathStartIndex == -1) { // e.g. for request lines like: 'GET http://myserver' (no final '/') - pathStartIndex = raw.Length; + // At this point we can return a path with a slash. + return new ArraySegment(_forwardSlashPath); } } else diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs index 72ba944f74..20ea25c514 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs @@ -114,6 +114,23 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } + [ConditionalFact] + public async Task Request_FullUriInRequestLine_ParsesPath() + { + string root; + using (var server = Utilities.CreateHttpServerReturnRoot("/", out root)) + { + // Send a HTTP request with the request line: + // GET http://localhost:5001 HTTP/1.1 + var responseTask = SendSocketRequestAsync(root, root); + var context = await server.AcceptAsync(Utilities.DefaultTimeout); + Assert.Equal("/", context.Request.Path); + Assert.Equal("", context.Request.PathBase); + Assert.Equal(root, context.Request.RawUrl); + Assert.False(root.EndsWith("/")); // make sure root doesn't have a trailing slash + } + } + [ConditionalFact] public async Task Request_OptionsStar_EmptyPath() { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs index 38ec6d0cb2..837c53340a 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs @@ -259,6 +259,42 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + [ConditionalFact] + public async Task Request_FullUriInRequestLine_ParsesPath() + { + using (var server = Utilities.CreateHttpServerReturnRoot("/", out var root, httpContext => + { + var requestInfo = httpContext.Features.Get(); + Assert.Equal("/", requestInfo.Path); + Assert.Equal("", requestInfo.PathBase); + return Task.CompletedTask; + })) + { + // Send a HTTP request with the request line: + // GET http://localhost:5001 HTTP/1.1 + var response = await SendSocketRequestAsync(root, root); + var responseStatusCode = response.Substring(9); // Skip "HTTP/1.1 " + Assert.Equal(StatusCodes.Status200OK.ToString(), responseStatusCode); + } + } + + [ConditionalFact] + public async Task Request_FullUriInRequestLineWithSlashesInQuery_BlockedByHttpSys() + { + using (var server = Utilities.CreateHttpServerReturnRoot("/", out var root, httpContext => + { + return Task.CompletedTask; + })) + { + // Send a HTTP request with the request line: + // GET http://localhost:5001?query=value/1/2 HTTP/1.1 + // Should return a 400 as it is a client error + var response = await SendSocketRequestAsync(root, root + "?query=value/1/2"); + var responseStatusCode = response.Substring(9); // Skip "HTTP/1.1 " + Assert.Equal(StatusCodes.Status400BadRequest.ToString(), responseStatusCode); + } + } + [ConditionalTheory] // The test server defines these prefixes: "/", "/11", "/2/3", "/2", "/11/2" [InlineData("/", "", "/")] From 9d9c8a26314a1227bfac8e2b0b99b522a965f8c9 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 17 Nov 2017 13:00:25 -0800 Subject: [PATCH 545/597] Use MicrosoftNETCoreApp21PackageVersion to determine the runtime framework in netcoreapp2.1 --- Directory.Build.targets | 1 + build/dependencies.props | 1 + 2 files changed, 2 insertions(+) diff --git a/Directory.Build.targets b/Directory.Build.targets index e83ff95e39..894b1d0cf8 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,5 +1,6 @@  $(MicrosoftNETCoreApp20PackageVersion) + $(MicrosoftNETCoreApp21PackageVersion) diff --git a/build/dependencies.props b/build/dependencies.props index 9bdf31e9da..b37c1c42c1 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -9,6 +9,7 @@ 2.1.0-preview1-27496 2.1.0-preview1-27496 2.0.0 + 2.1.0-preview1-25907-02 2.1.0-preview1-27496 15.3.0 4.4.0 From 453ab556150d4944ad70b6f85c2ecbc8b8ef3a41 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 20 Nov 2017 12:16:00 -0800 Subject: [PATCH 546/597] Use MSBuild to set NuGet feeds instead of NuGet.config --- Directory.Build.props | 1 + NuGet.config | 4 +--- build/sources.props | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 build/sources.props diff --git a/Directory.Build.props b/Directory.Build.props index 36f05acd3b..13a3c749b4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,6 +5,7 @@ + Microsoft ASP.NET Core diff --git a/NuGet.config b/NuGet.config index 4e8a1f6de1..e32bddfd51 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,8 +2,6 @@ - - - + diff --git a/build/sources.props b/build/sources.props new file mode 100644 index 0000000000..c03f3ddb60 --- /dev/null +++ b/build/sources.props @@ -0,0 +1,16 @@ + + + + + $(DotNetRestoreSources) + + $(RestoreSources); + https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; + + + $(RestoreSources); + https://api.nuget.org/v3/index.json; + + + From ec1eaa67913cd8faaf8e9a1a39d7a282bb3a41cf Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 21 Nov 2017 15:47:57 -0800 Subject: [PATCH 547/597] Replace aspnetcore-ci-dev feed with aspnetcore-dev --- build/dependencies.props | 14 +++++++------- build/repo.props | 2 +- build/sources.props | 2 +- korebuild-lock.txt | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index b37c1c42c1..8b65587cd8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,16 +1,16 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15549 - 2.1.0-preview1-27496 - 2.1.0-preview1-27496 - 2.1.0-preview1-27496 - 2.1.0-preview1-27496 + 2.1.0-preview1-15576 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 + 2.1.0-preview1-27644 2.0.0 2.1.0-preview1-25907-02 - 2.1.0-preview1-27496 + 2.1.0-preview1-27644 15.3.0 4.4.0 4.4.0 diff --git a/build/repo.props b/build/repo.props index b55e651b87..07c5f08325 100644 --- a/build/repo.props +++ b/build/repo.props @@ -2,6 +2,6 @@ Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index c03f3ddb60..9feff29d09 100644 --- a/build/sources.props +++ b/build/sources.props @@ -5,7 +5,7 @@ $(DotNetRestoreSources) $(RestoreSources); - https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 95f4613014..1a99066b7c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15567 -commithash:903e3104807b1bb8cddd28bdef205b1e2dc021d1 +version:2.1.0-preview1-15576 +commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 From ede025fe3417c08011456942a17810a2e108ae6a Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 29 Nov 2017 14:09:26 -0800 Subject: [PATCH 548/597] Specify runtime versions to install --- build/repo.props | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/repo.props b/build/repo.props index 07c5f08325..78b0ce5879 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,7 +1,14 @@  + + Internal.AspNetCore.Universe.Lineup https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + + + + + From 14aec22cda2c0c81b369b08c7d260afffae20c9d Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Fri, 1 Dec 2017 10:24:09 -0800 Subject: [PATCH 549/597] Update bootstrappers --- run.ps1 | 17 +++++++++++------ run.sh | 30 +++++++++++++++++++----------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/run.ps1 b/run.ps1 index 49c2899856..27dcf848f8 100644 --- a/run.ps1 +++ b/run.ps1 @@ -29,6 +29,9 @@ Updates KoreBuild to the latest version even if a lock file is present. .PARAMETER ConfigFile The path to the configuration file that stores values. Defaults to korebuild.json. +.PARAMETER ToolsSourceSuffix +The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. + .PARAMETER Arguments Arguments to be passed to the command @@ -51,7 +54,7 @@ Example config file: #> [CmdletBinding(PositionalBinding = $false)] param( - [Parameter(Mandatory=$true, Position = 0)] + [Parameter(Mandatory = $true, Position = 0)] [string]$Command, [string]$Path = $PSScriptRoot, [Alias('c')] @@ -63,6 +66,7 @@ param( [Alias('u')] [switch]$Update, [string]$ConfigFile, + [string]$ToolsSourceSuffix, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$Arguments ) @@ -79,7 +83,7 @@ function Get-KoreBuild { $lockFile = Join-Path $Path 'korebuild-lock.txt' if (!(Test-Path $lockFile) -or $Update) { - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix } $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 @@ -96,7 +100,7 @@ function Get-KoreBuild { try { $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" - Get-RemoteFile $remotePath $tmpfile + Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { # Use built-in commands where possible as they are cross-plat compatible Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath @@ -124,7 +128,7 @@ function Join-Paths([string]$path, [string[]]$childPaths) { return $path } -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { if ($RemotePath -notlike 'http*') { Copy-Item $RemotePath $LocalPath return @@ -134,7 +138,7 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) { while ($retries -gt 0) { $retries -= 1 try { - Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath + Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath return } catch { @@ -161,7 +165,8 @@ if (Test-Path $ConfigFile) { if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} } - } catch { + } + catch { Write-Warning "$ConfigFile could not be read. Its settings will be ignored." Write-Warning $Error[0] } diff --git a/run.sh b/run.sh index c278423acc..834961fc3a 100755 --- a/run.sh +++ b/run.sh @@ -17,6 +17,7 @@ update=false repo_path="$DIR" channel='' tools_source='' +tools_source_suffix='' # # Functions @@ -29,13 +30,14 @@ __usage() { echo " ... Arguments passed to the command. Variable number of arguments allowed." echo "" echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." echo "" echo "Description:" echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." @@ -50,7 +52,7 @@ get_korebuild() { local version local lock_file="$repo_path/korebuild-lock.txt" if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" fi version="$(grep 'version:*' -m 1 "$lock_file")" if [[ "$version" == '' ]]; then @@ -66,7 +68,7 @@ get_korebuild() { local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile"; then + if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then unzip -q -d "$korebuild_path" "$tmpfile" fi rm "$tmpfile" || true @@ -98,6 +100,7 @@ __machine_has() { __get_remote_file() { local remote_path=$1 local local_path=$2 + local remote_path_suffix=$3 if [[ "$remote_path" != 'http'* ]]; then cp "$remote_path" "$local_path" @@ -106,14 +109,14 @@ __get_remote_file() { local failed=false if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true + wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true else failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true fi if [ "$failed" = true ]; then @@ -164,6 +167,11 @@ while [[ $# -gt 0 ]]; do tools_source="${1:-}" [ -z "$tools_source" ] && __usage ;; + --tools-source-suffix|-ToolsSourceSuffix) + shift + tools_source_suffix="${1:-}" + [ -z "$tools_source_suffix" ] && __usage + ;; -u|--update|-Update) update=true ;; From 3fdcd13c59de12d7d257ce7d4951c88a3d175dee Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 10 Dec 2017 12:50:46 -0800 Subject: [PATCH 550/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 24 ++++++++++++------------ korebuild-lock.txt | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 8b65587cd8..9b9fb8cfb6 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,20 +3,20 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15576 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 - 2.1.0-preview1-27644 + 2.1.0-preview1-15618 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 + 2.1.0-preview1-27773 2.0.0 - 2.1.0-preview1-25907-02 - 2.1.0-preview1-27644 + 2.1.0-preview1-25915-01 + 2.1.0-preview1-27773 15.3.0 - 4.4.0 - 4.4.0 - 4.4.0 - 2.3.0 - 2.3.0 + 4.5.0-preview1-25914-04 + 4.5.0-preview1-25914-04 + 4.5.0-preview1-25914-04 + 2.3.1 + 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 1a99066b7c..e7cce93009 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15576 -commithash:2f3856d2ba4f659fcb9253215b83946a06794a27 +version:2.1.0-preview1-15618 +commithash:00ce1383114015fe89b221146036e59e6bc11219 From 4f7fd40f8cea9e64950dd64afbb17c2186fe5c8f Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Wed, 13 Dec 2017 20:51:51 +0000 Subject: [PATCH 551/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 20 ++++++++++---------- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 9b9fb8cfb6..24bc2b23c8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15618 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 - 2.1.0-preview1-27773 + 2.1.0-preview1-15626 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 + 2.1.0-preview1-27807 2.0.0 - 2.1.0-preview1-25915-01 - 2.1.0-preview1-27773 + 2.1.0-preview1-26008-01 + 2.1.0-preview1-27807 15.3.0 - 4.5.0-preview1-25914-04 - 4.5.0-preview1-25914-04 - 4.5.0-preview1-25914-04 + 4.5.0-preview1-26006-06 + 4.5.0-preview1-26006-06 + 4.5.0-preview1-26006-06 2.3.1 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e7cce93009..8d52a6128c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15618 -commithash:00ce1383114015fe89b221146036e59e6bc11219 +version:2.1.0-preview1-15626 +commithash:fd6410e9c90c428bc01238372303ad09cb9ec889 From 269ed40c3c6dbb1153f78856bf0d6a353605b97f Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 18 Dec 2017 17:06:22 -0800 Subject: [PATCH 552/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 24bc2b23c8..5625d558fe 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,17 +4,17 @@ 2.1.0-preview1-15626 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 - 2.1.0-preview1-27807 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 + 2.1.0-preview1-27849 2.0.0 - 2.1.0-preview1-26008-01 - 2.1.0-preview1-27807 + 2.1.0-preview1-26016-05 + 2.1.0-preview1-27849 15.3.0 - 4.5.0-preview1-26006-06 - 4.5.0-preview1-26006-06 - 4.5.0-preview1-26006-06 + 4.5.0-preview1-26016-05 + 4.5.0-preview1-26016-05 + 4.5.0-preview1-26016-05 2.3.1 2.3.1 From fc58ab8033a1cb4ad5eb50b80d1682fe610ead17 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 31 Dec 2017 21:07:53 +0000 Subject: [PATCH 553/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5625d558fe..f50c06914e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,14 +3,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15626 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 - 2.1.0-preview1-27849 + 2.1.0-preview1-15651 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 + 2.1.0-preview1-27942 2.0.0 2.1.0-preview1-26016-05 - 2.1.0-preview1-27849 + 2.1.0-preview1-27942 15.3.0 4.5.0-preview1-26016-05 4.5.0-preview1-26016-05 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 8d52a6128c..7c2e97aa79 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15626 -commithash:fd6410e9c90c428bc01238372303ad09cb9ec889 +version:2.1.0-preview1-15651 +commithash:ebf2365121c2c6a6a0fbfa9b0f37bb5effc89323 From 60484d001a55e70e3a78a2fd730ccc1b33abeb52 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 4 Jan 2018 01:14:32 +0000 Subject: [PATCH 554/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index f50c06914e..c76aaabc0e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,13 +4,13 @@ 2.1.0-preview1-15651 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 - 2.1.0-preview1-27942 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 + 2.1.0-preview1-27965 2.0.0 2.1.0-preview1-26016-05 - 2.1.0-preview1-27942 + 2.1.0-preview1-27965 15.3.0 4.5.0-preview1-26016-05 4.5.0-preview1-26016-05 From 8806b50c30770b0d8db47e5a2c36e9f9e65f343f Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sat, 6 Jan 2018 14:46:25 -0800 Subject: [PATCH 555/597] Update dependencies.props [auto-updated: dependencies] --- korebuild-lock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 7c2e97aa79..2146d006d7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15651 -commithash:ebf2365121c2c6a6a0fbfa9b0f37bb5effc89323 +version:2.1.0-preview1-15661 +commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 From 2e0c505002dfe94a90b9bdb59daf20c4e6725603 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 23 Jan 2018 15:31:22 -0800 Subject: [PATCH 556/597] Branching for 2.1.0-preview1 --- build/dependencies.props | 20 ++++++++++---------- build/repo.props | 4 ++-- build/sources.props | 4 ++-- korebuild-lock.txt | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c76aaabc0e..ae4dea95b8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15651 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 + 2.1.0-preview1-15679 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 + 2.1.0-preview1-28153 2.0.0 - 2.1.0-preview1-26016-05 - 2.1.0-preview1-27965 + 2.1.0-preview1-26115-03 + 2.1.0-preview1-28153 15.3.0 - 4.5.0-preview1-26016-05 - 4.5.0-preview1-26016-05 - 4.5.0-preview1-26016-05 + 4.5.0-preview1-26112-01 + 4.5.0-preview1-26112-01 + 4.5.0-preview1-26112-01 2.3.1 2.3.1 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..d94ff7d00d 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,10 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index 9feff29d09..5d66393335 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,11 +1,11 @@ - + $(DotNetRestoreSources) $(RestoreSources); - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2146d006d7..a474bc0e35 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15661 -commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 +version:2.1.0-preview1-15679 +commithash:5347461137cb45a77ddcc0b55b2478092de43338 From e40cf72fcefc5ab86678930f114821f4fdafe5a5 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 24 Jan 2018 15:00:27 -0800 Subject: [PATCH 557/597] Updating version to preview2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 5c4a7c32d1..370d5ababd 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview1 + preview2 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From c4904acddadfc69a6da83e17ce771333de02dcab Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 31 Jan 2018 15:01:11 -0800 Subject: [PATCH 558/597] Update dependencies.props to 2.1.0-preview-28193, build tools to 2.1.0-preview1-1010 [ci skip] Scripted changes: - updated travis and appveyor.yml files to only build dev, ci, and release branches - updated dependencies.props - updated korebuild-lock.txt - updated korebuild.json to release/2.1 channel --- .appveyor.yml | 15 +++++++-------- .travis.yml | 23 ++++++++++++----------- build/dependencies.props | 20 ++++++++++---------- korebuild-lock.txt | 4 ++-- korebuild.json | 4 ++-- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 46038786c9..4eea96ab69 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,18 +1,17 @@ init: - - git config --global core.autocrlf true +- git config --global core.autocrlf true branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - dev + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ build_script: - - ps: .\run.ps1 default-build +- ps: .\run.ps1 default-build clone_depth: 1 environment: global: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 -test: off -deploy: off +test: 'off' +deploy: 'off' os: Visual Studio 2017 diff --git a/.travis.yml b/.travis.yml index b10be14215..64bdbb4441 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,24 +3,25 @@ sudo: false dist: trusty env: global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 mono: none os: - - linux - - osx +- linux +- osx osx_image: xcode8.2 addons: apt: packages: - - libunwind8 + - libunwind8 branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - dev + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi +- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s + /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib + /usr/local/lib/; fi script: - - ./build.sh +- ./build.sh diff --git a/build/dependencies.props b/build/dependencies.props index ae4dea95b8..14677c6e2e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15679 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 - 2.1.0-preview1-28153 + 2.1.0-preview1-1010 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 + 2.1.0-preview1-28193 2.0.0 - 2.1.0-preview1-26115-03 - 2.1.0-preview1-28153 + 2.1.0-preview1-26122-01 + 2.1.0-preview1-28193 15.3.0 - 4.5.0-preview1-26112-01 - 4.5.0-preview1-26112-01 - 4.5.0-preview1-26112-01 + 4.5.0-preview1-26119-06 + 4.5.0-preview1-26119-06 + 4.5.0-preview1-26119-06 2.3.1 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index a474bc0e35..851bfbf203 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15679 -commithash:5347461137cb45a77ddcc0b55b2478092de43338 +version:2.1.0-preview1-1010 +commithash:75ca924dfbd673c38841025b04c4dcd93b84f56d diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } From 2164b80e4c54cd570fc63b2e23e4037ee7342318 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 1 Feb 2018 03:31:52 +0000 Subject: [PATCH 559/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 20 ++++++++++---------- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index c76aaabc0e..59697bd3f7 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview1-15651 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 - 2.1.0-preview1-27965 + 2.1.0-preview2-15692 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 + 2.1.0-preview2-28215 2.0.0 - 2.1.0-preview1-26016-05 - 2.1.0-preview1-27965 + 2.1.0-preview2-26130-04 + 2.1.0-preview2-28215 15.3.0 - 4.5.0-preview1-26016-05 - 4.5.0-preview1-26016-05 - 4.5.0-preview1-26016-05 + 4.5.0-preview2-26130-01 + 4.5.0-preview2-26130-01 + 4.5.0-preview2-26130-01 2.3.1 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 2146d006d7..232cb858c2 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview1-15661 -commithash:c9349d4c8a495d3085d9b879214d80f2f45e2193 +version:2.1.0-preview2-15692 +commithash:5d9f445ce3f8492451a6f461df7e739bbed6a7f8 From 55d05b553451e10344aedf59759059154489bc23 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sat, 3 Feb 2018 02:47:26 +0000 Subject: [PATCH 560/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 59697bd3f7..cc69bb4129 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,14 +3,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15692 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 - 2.1.0-preview2-28215 + 2.1.0-preview2-15694 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 + 2.1.0-preview2-30020 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-28215 + 2.1.0-preview2-30020 15.3.0 4.5.0-preview2-26130-01 4.5.0-preview2-26130-01 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 232cb858c2..6f294ef0e6 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15692 -commithash:5d9f445ce3f8492451a6f461df7e739bbed6a7f8 +version:2.1.0-preview2-15694 +commithash:f61af02b48e89592c9aadb7ebaebe84228666c3b From fd1144cf2f2f2db2b87fd33e30a2bbdd25c3fae5 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 9 Feb 2018 11:44:25 -0800 Subject: [PATCH 561/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index cc69bb4129..240bd3be6c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,14 +3,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15694 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 - 2.1.0-preview2-30020 + 2.1.0-preview2-15698 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 + 2.1.0-preview2-30066 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-30020 + 2.1.0-preview2-30066 15.3.0 4.5.0-preview2-26130-01 4.5.0-preview2-26130-01 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 6f294ef0e6..3e2b56b91b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15694 -commithash:f61af02b48e89592c9aadb7ebaebe84228666c3b +version:2.1.0-preview2-15698 +commithash:7216e5068cb1957e09d45fcbe58a744dd5c2de73 From 7d37e938d42dcc50611b9161247eeabc44db29d0 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 11 Feb 2018 12:25:42 -0800 Subject: [PATCH 562/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 240bd3be6c..12eb169d1c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,19 +4,19 @@ 2.1.0-preview2-15698 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 - 2.1.0-preview2-30066 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 + 2.1.0-preview2-30077 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-30066 + 2.1.0-preview2-30077 15.3.0 4.5.0-preview2-26130-01 4.5.0-preview2-26130-01 4.5.0-preview2-26130-01 2.3.1 - 2.3.1 + 2.4.0-beta.1.build3945 From 264354afbef716433571f5ee31070799f233e644 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 18 Feb 2018 12:19:03 -0800 Subject: [PATCH 563/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 12eb169d1c..a7599836d4 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,14 +3,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15698 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 - 2.1.0-preview2-30077 + 2.1.0-preview2-15707 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 + 2.1.0-preview2-30131 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-30077 + 2.1.0-preview2-30131 15.3.0 4.5.0-preview2-26130-01 4.5.0-preview2-26130-01 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3e2b56b91b..89d0ad3d15 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15698 -commithash:7216e5068cb1957e09d45fcbe58a744dd5c2de73 +version:2.1.0-preview2-15707 +commithash:e74e53f129ab34332947fea7ac7b7591b027cb22 From 3261ba52cf5adf73a3b773f502f97449be2c475f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 21 Feb 2018 18:26:58 -0800 Subject: [PATCH 564/597] Use FeatureBranchVersionSuffix when generating VersionSuffix --- version.props | 1 + 1 file changed, 1 insertion(+) diff --git a/version.props b/version.props index 370d5ababd..65c8a07e37 100644 --- a/version.props +++ b/version.props @@ -5,6 +5,7 @@ $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 + $(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) From 6bf39a741d6eb0e5e364b19533fc06e131a1ab4e Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Mon, 26 Feb 2018 11:02:58 -0800 Subject: [PATCH 565/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 14 +++++++------- korebuild-lock.txt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index a7599836d4..5524532622 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,15 +3,15 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15707 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 - 2.1.0-preview2-30131 + 2.1.0-preview2-15721 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 + 2.1.0-preview2-30187 2.0.0 2.1.0-preview2-26130-04 - 2.1.0-preview2-30131 - 15.3.0 + 2.1.0-preview2-30187 + 15.6.0 4.5.0-preview2-26130-01 4.5.0-preview2-26130-01 4.5.0-preview2-26130-01 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 89d0ad3d15..e6c7fddffa 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15707 -commithash:e74e53f129ab34332947fea7ac7b7591b027cb22 +version:2.1.0-preview2-15721 +commithash:f9bb4be59e39938ec59a6975257e26099b0d03c1 From 0b6607d92cae2b69f87a269531817428eb2d2cc8 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 6 Mar 2018 10:04:08 -0800 Subject: [PATCH 566/597] Use dotnet-core feed in repos --- build/sources.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/sources.props b/build/sources.props index 9feff29d09..9215df9751 100644 --- a/build/sources.props +++ b/build/sources.props @@ -1,10 +1,11 @@ - + $(DotNetRestoreSources) $(RestoreSources); + https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; From 336e85d19abcdf3ec3a024cb9431c768a4e5d494 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 6 Mar 2018 10:04:08 -0800 Subject: [PATCH 567/597] Prepend FeatureBranchVersionPrefix if FeatureBranchVersionSuffix is specified --- version.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/version.props b/version.props index 65c8a07e37..a11ea1ed52 100644 --- a/version.props +++ b/version.props @@ -5,7 +5,8 @@ $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 - $(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) + a- + $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) $(VersionSuffix)-$(BuildNumber) From dbd557c9657f144c327b6e56f5289685a83c33ee Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Tue, 6 Mar 2018 20:25:51 -0800 Subject: [PATCH 568/597] Exclude the upgrade feature if the OS does not support it #427 --- .../StandardFeatureCollection.cs | 12 ++- .../OSDontSkipConditionAttribute.cs | 99 +++++++++++++++++++ .../OpaqueUpgradeTests.cs | 26 +++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs index 0830de0fec..2adf51d1fc 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs @@ -22,7 +22,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys // { typeof(ITlsTokenBindingFeature), ctx => ctx.GetTlsTokenBindingFeature() }, TODO: https://github.com/aspnet/HttpSysServer/issues/231 { typeof(IHttpBufferingFeature), _identityFunc }, { typeof(IHttpRequestLifetimeFeature), _identityFunc }, - { typeof(IHttpUpgradeFeature), _identityFunc }, { typeof(IHttpAuthenticationFeature), _identityFunc }, { typeof(IHttpRequestIdentifierFeature), _identityFunc }, { typeof(RequestContext), ctx => ctx.RequestContext }, @@ -32,6 +31,17 @@ namespace Microsoft.AspNetCore.Server.HttpSys private readonly FeatureContext _featureContext; + static StandardFeatureCollection() + { + if (ComNetOS.IsWin8orLater) + { + // Only add the upgrade feature if it stands a chance of working. + // SignalR uses the presence of the feature to detect feature support. + // https://github.com/aspnet/HttpSysServer/issues/427 + _featureFuncLookup[typeof(IHttpUpgradeFeature)] = _identityFunc; + } + } + public StandardFeatureCollection(FeatureContext featureContext) { _featureContext = featureContext; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs new file mode 100644 index 0000000000..c657240a3e --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs @@ -0,0 +1,99 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNetCore.Testing.xunit +{ + // Skip except on a specific OS and version + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] + public class OSDontSkipConditionAttribute : Attribute, ITestCondition + { + private readonly OperatingSystems _includedOperatingSystem; + private readonly IEnumerable _includedVersions; + private readonly OperatingSystems _osPlatform; + private readonly string _osVersion; + + public OSDontSkipConditionAttribute(OperatingSystems operatingSystem, params string[] versions) : + this( + operatingSystem, + GetCurrentOS(), + GetCurrentOSVersion(), + versions) + { + } + + // to enable unit testing + internal OSDontSkipConditionAttribute( + OperatingSystems operatingSystem, OperatingSystems osPlatform, string osVersion, params string[] versions) + { + _includedOperatingSystem = operatingSystem; + _includedVersions = versions ?? Enumerable.Empty(); + _osPlatform = osPlatform; + _osVersion = osVersion; + } + + public bool IsMet + { + get + { + var currentOSInfo = new OSInfo() + { + OperatingSystem = _osPlatform, + Version = _osVersion, + }; + + var skip = (_includedOperatingSystem & currentOSInfo.OperatingSystem) != currentOSInfo.OperatingSystem; + if (!skip && _includedVersions.Any()) + { + skip = !_includedVersions.Any(inc => _osVersion.StartsWith(inc, StringComparison.OrdinalIgnoreCase)); + } + + // Since a test would be excuted only if 'IsMet' is true, return false if we want to skip + return !skip; + } + } + + public string SkipReason { get; set; } = "Test cannot run on this operating system."; + + static private OperatingSystems GetCurrentOS() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return OperatingSystems.Windows; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return OperatingSystems.Linux; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return OperatingSystems.MacOSX; + } + throw new PlatformNotSupportedException(); + } + + static private string GetCurrentOSVersion() + { + // currently not used on other OS's + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Environment.OSVersion.Version.ToString(); + } + else + { + return string.Empty; + } + } + + private class OSInfo + { + public OperatingSystems OperatingSystem { get; set; } + + public string Version { get; set; } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs index c0fdda0dd2..609bc59fdd 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs @@ -17,6 +17,32 @@ namespace Microsoft.AspNetCore.Server.HttpSys { public class OpaqueUpgradeTests { + [ConditionalFact] + [OSDontSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] + public async Task OpaqueUpgrade_DownLevel_FeatureIsAbsent() + { + using (Utilities.CreateHttpServer(out var address, httpContext => + { + try + { + var opaqueFeature = httpContext.Features.Get(); + Assert.Null(opaqueFeature); + } + catch (Exception ex) + { + return httpContext.Response.WriteAsync(ex.ToString()); + } + return Task.FromResult(0); + })) + { + HttpResponseMessage response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.False(response.Headers.TransferEncodingChunked.HasValue, "Chunked"); + Assert.Equal(0, response.Content.Headers.ContentLength); + Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync()); + } + } + [ConditionalFact] [OSSkipCondition(OperatingSystems.Windows, WindowsVersions.Win7, WindowsVersions.Win2008R2)] public async Task OpaqueUpgrade_SupportKeys_Present() From 80345b7f8ffd7a2b623d2e449f6854e3037c1ccc Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 8 Mar 2018 13:01:30 -0800 Subject: [PATCH 569/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 20 ++++++++++---------- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5524532622..f2976b08b8 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15721 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 - 2.1.0-preview2-30187 + 2.1.0-preview2-15728 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 + 2.1.0-preview2-30272 2.0.0 - 2.1.0-preview2-26130-04 - 2.1.0-preview2-30187 + 2.1.0-preview2-26225-03 + 2.1.0-preview2-30272 15.6.0 - 4.5.0-preview2-26130-01 - 4.5.0-preview2-26130-01 - 4.5.0-preview2-26130-01 + 4.5.0-preview2-26224-02 + 4.5.0-preview2-26224-02 + 4.5.0-preview2-26224-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e6c7fddffa..138d848db1 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15721 -commithash:f9bb4be59e39938ec59a6975257e26099b0d03c1 +version:2.1.0-preview2-15728 +commithash:393377068ddcf51dfee0536536d455f57a828b06 From fbc5b64cd8fee5e966b51ce0dbb9f32fd524fce4 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 16 Mar 2018 10:56:36 -0700 Subject: [PATCH 570/597] React to new SocketHttpHandler (#434) --- build/dependencies.props | 18 +- .../RequestProcessing/RequestStream.cs | 227 +++++++++--------- .../Listener/RequestBodyTests.cs | 3 +- .../Listener/ResponseBodyTests.cs | 8 +- .../Listener/ResponseSendFileTests.cs | 4 +- .../Listener/ServerTests.cs | 4 +- .../RequestBodyLimitTests.cs | 1 + .../RequestBodyTests.cs | 3 +- 8 files changed, 131 insertions(+), 137 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index f2976b08b8..5aaa28edec 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,17 +4,17 @@ 2.1.0-preview2-15728 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 + 2.1.0-preview2-30301 + 2.1.0-preview2-30301 + 2.1.0-preview2-30301 + 2.1.0-preview2-30301 2.0.0 - 2.1.0-preview2-26225-03 - 2.1.0-preview2-30272 + 2.1.0-preview2-26308-01 + 2.1.0-preview2-30301 15.6.0 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index 284a3d856e..6e0cb2ace5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -133,12 +133,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); } - if (_dataChunkIndex == -1 && dataRead < size) + if (_dataChunkIndex == -1 && dataRead == 0) { uint statusCode = 0; uint extraDataRead = 0; - offset += (int)dataRead; - size -= (int)dataRead; // the http.sys team recommends that we limit the size to 128kb if (size > MaxReadSize) @@ -209,72 +207,68 @@ namespace Microsoft.AspNetCore.Server.HttpSys { dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); - if (_dataChunkIndex != -1 && dataRead == size) + if (dataRead > 0) { asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, 0); asyncResult.Complete((int)dataRead); + return asyncResult; } } - if (_dataChunkIndex == -1 && dataRead < size) + uint statusCode = 0; + + // the http.sys team recommends that we limit the size to 128kb + if (size > MaxReadSize) { - uint statusCode = 0; - offset += (int)dataRead; - size -= (int)dataRead; + size = MaxReadSize; + } - // the http.sys team recommends that we limit the size to 128kb - if (size > MaxReadSize) - { - size = MaxReadSize; - } + asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, dataRead); + uint bytesReturned; - asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, dataRead); - uint bytesReturned; + try + { + uint flags = 0; - try - { - uint flags = 0; + statusCode = + HttpApi.HttpReceiveRequestEntityBody( + RequestQueueHandle, + RequestId, + flags, + asyncResult.PinnedBuffer, + (uint)size, + out bytesReturned, + asyncResult.NativeOverlapped); + } + catch (Exception e) + { + LogHelper.LogException(Logger, "BeginRead", e); + asyncResult.Dispose(); + throw; + } - statusCode = - HttpApi.HttpReceiveRequestEntityBody( - RequestQueueHandle, - RequestId, - flags, - asyncResult.PinnedBuffer, - (uint)size, - out bytesReturned, - asyncResult.NativeOverlapped); - } - catch (Exception e) + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - LogHelper.LogException(Logger, "BeginRead", e); - asyncResult.Dispose(); - throw; + asyncResult = new RequestStreamAsyncResult(this, state, callback, dataRead); + asyncResult.Complete((int)bytesReturned); } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + else { - asyncResult.Dispose(); - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) - { - asyncResult = new RequestStreamAsyncResult(this, state, callback, dataRead); - asyncResult.Complete((int)bytesReturned); - } - else - { - Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); - LogHelper.LogException(Logger, "BeginRead", exception); - Abort(); - throw exception; - } - } - else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - HttpSysListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously - callback won't be called to signal completion. - asyncResult.IOCompleted(statusCode, bytesReturned); + Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); + LogHelper.LogException(Logger, "BeginRead", exception); + Abort(); + throw exception; } } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + HttpSysListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.IOCompleted(statusCode, bytesReturned); + } return asyncResult; } @@ -322,7 +316,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (_dataChunkIndex != -1) { dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); - if (_dataChunkIndex != -1 && dataRead == size) + if (dataRead > 0) { UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead); if (TryCheckSizeLimit((int)dataRead, out var exception)) @@ -334,85 +328,82 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - if (_dataChunkIndex == -1 && dataRead < size) + uint statusCode = 0; + offset += (int)dataRead; + size -= (int)dataRead; + + // the http.sys team recommends that we limit the size to 128kb + if (size > MaxReadSize) { - uint statusCode = 0; - offset += (int)dataRead; - size -= (int)dataRead; + size = MaxReadSize; + } - // the http.sys team recommends that we limit the size to 128kb - if (size > MaxReadSize) - { - size = MaxReadSize; - } + var cancellationRegistration = default(CancellationTokenRegistration); + if (cancellationToken.CanBeCanceled) + { + cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); + } - var cancellationRegistration = default(CancellationTokenRegistration); - if (cancellationToken.CanBeCanceled) - { - cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); - } + asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration); + uint bytesReturned; - asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration); - uint bytesReturned; + try + { + uint flags = 0; - try - { - uint flags = 0; + statusCode = + HttpApi.HttpReceiveRequestEntityBody( + RequestQueueHandle, + RequestId, + flags, + asyncResult.PinnedBuffer, + (uint)size, + out bytesReturned, + asyncResult.NativeOverlapped); + } + catch (Exception e) + { + asyncResult.Dispose(); + Abort(); + LogHelper.LogException(Logger, "ReadAsync", e); + throw; + } - statusCode = - HttpApi.HttpReceiveRequestEntityBody( - RequestQueueHandle, - RequestId, - flags, - asyncResult.PinnedBuffer, - (uint)size, - out bytesReturned, - asyncResult.NativeOverlapped); - } - catch (Exception e) + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - asyncResult.Dispose(); - Abort(); - LogHelper.LogException(Logger, "ReadAsync", e); - throw; - } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) - { - asyncResult.Dispose(); - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) - { - uint totalRead = dataRead + bytesReturned; - UpdateAfterRead(statusCode, totalRead); - if (TryCheckSizeLimit((int)totalRead, out var exception)) - { - return Task.FromException(exception); - } - // TODO: Verbose log totalRead - return Task.FromResult((int)totalRead); - } - else - { - Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); - LogHelper.LogException(Logger, "ReadAsync", exception); - Abort(); - throw exception; - } - } - else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - HttpSysListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously - callback won't be called to signal completion. - asyncResult.Dispose(); uint totalRead = dataRead + bytesReturned; UpdateAfterRead(statusCode, totalRead); if (TryCheckSizeLimit((int)totalRead, out var exception)) { return Task.FromException(exception); } - // TODO: Verbose log + // TODO: Verbose log totalRead return Task.FromResult((int)totalRead); } + else + { + Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); + LogHelper.LogException(Logger, "ReadAsync", exception); + Abort(); + throw exception; + } + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + HttpSysListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.Dispose(); + uint totalRead = dataRead + bytesReturned; + UpdateAfterRead(statusCode, totalRead); + if (TryCheckSizeLimit((int)totalRead, out var exception)) + { + return Task.FromException(exception); + } + // TODO: Verbose log + return Task.FromResult((int)totalRead); } return asyncResult.Task; } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index 9ea7f4805f..baec5a8204 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -344,7 +344,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener content.Block.Release(); context.Dispose(); - await Assert.ThrowsAsync(async () => await responseTask); + await Assert.ThrowsAnyAsync(async () => await responseTask); } } @@ -421,6 +421,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) { await stream.WriteAsync(new byte[5], 0, 5); + await stream.FlushAsync(); await Block.WaitAsync(); await stream.WriteAsync(new byte[5], 0, 5); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index ef56e997cb..0c91833773 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -427,7 +427,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); Assert.Throws(() => { @@ -458,7 +458,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); await Assert.ThrowsAsync(async () => @@ -489,7 +489,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. for (int i = 0; i < Utilities.WriteRetryLimit; i++) @@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. for (int i = 0; i < Utilities.WriteRetryLimit; i++) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index 2a962c69f2..990af071e7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -468,7 +468,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); await Assert.ThrowsAsync(async () => @@ -499,7 +499,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Send notices the disconnect. for (int i = 0; i < Utilities.WriteRetryLimit; i++) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index 60c95a94f1..c15d47fd15 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(canceled.WaitOne(interval), "canceled"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); context.Dispose(); } @@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); client.CancelPendingRequests(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs index ebc0fa9f98..ae203ceab1 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs @@ -413,6 +413,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) { await stream.WriteAsync(new byte[10], 0, 10); + await stream.FlushAsync(); Assert.True(await Block.WaitAsync(TimeSpan.FromSeconds(10))); await stream.WriteAsync(new byte[10], 0, 10); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs index 1b87920103..b7a18867d9 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs @@ -232,7 +232,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) { await stream.WriteAsync(new byte[5], 0, 5); - await Block.WaitAsync(); + await stream.FlushAsync(); + Assert.True(await Block.WaitAsync(TimeSpan.FromSeconds(10))); await stream.WriteAsync(new byte[5], 0, 5); } From 0076eb1924d2f6defe5f88d6472d97e1d39c01fe Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 11:14:57 -0700 Subject: [PATCH 571/597] Branching for 2.1.0-preview2 --- build/dependencies.props | 20 ++++++++++---------- build/repo.props | 4 ++-- build/sources.props | 2 +- korebuild-lock.txt | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5aaa28edec..7fac827a6e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15728 - 2.1.0-preview2-30301 - 2.1.0-preview2-30301 - 2.1.0-preview2-30301 - 2.1.0-preview2-30301 + 2.1.0-preview2-15742 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 + 2.1.0-preview2-30355 2.0.0 - 2.1.0-preview2-26308-01 - 2.1.0-preview2-30301 + 2.1.0-preview2-26314-02 + 2.1.0-preview2-30355 15.6.0 - 4.5.0-preview2-26308-02 - 4.5.0-preview2-26308-02 - 4.5.0-preview2-26308-02 + 4.5.0-preview2-26313-01 + 4.5.0-preview2-26313-01 + 4.5.0-preview2-26313-01 2.3.1 2.4.0-beta.1.build3945 diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..d94ff7d00d 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,10 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json diff --git a/build/sources.props b/build/sources.props index 9215df9751..36045f12b5 100644 --- a/build/sources.props +++ b/build/sources.props @@ -6,7 +6,7 @@ $(RestoreSources); https://dotnet.myget.org/F/dotnet-core/api/v3/index.json; - https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; + https://dotnet.myget.org/F/aspnetcore-release/api/v3/index.json; https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json; diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 138d848db1..e40ef6651b 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15728 -commithash:393377068ddcf51dfee0536536d455f57a828b06 +version:2.1.0-preview2-15742 +commithash:21fbb0f2c3fe4a9216e2d59632b98cfd7d685962 From a35be9ee4b43420864eb7ada190731f4087ddd8e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 11:26:36 -0700 Subject: [PATCH 572/597] Update version prefix to preview3 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index a11ea1ed52..24f2b00a0a 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview2 + preview3 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From b5de1f0dbec25a82c047d500b6bb5d9b411916d3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 16 Mar 2018 12:30:15 -0700 Subject: [PATCH 573/597] Update KoreBuild channel --- korebuild.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } From 7dd042482500216f7a66c0a4b0cbae0ad30fcec6 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 14 Mar 2018 15:34:09 -0700 Subject: [PATCH 574/597] Set 2.0 baselines --- build/dependencies.props | 2 +- korebuild-lock.txt | 4 +- .../baseline.netcore.json | 828 ++++++++++++++++++ 3 files changed, 831 insertions(+), 3 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json diff --git a/build/dependencies.props b/build/dependencies.props index 7fac827a6e..d779b90b03 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,7 +3,7 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15742 + 2.1.0-preview2-15744 2.1.0-preview2-30355 2.1.0-preview2-30355 2.1.0-preview2-30355 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index e40ef6651b..f531e7b0f7 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15742 -commithash:21fbb0f2c3fe4a9216e2d59632b98cfd7d685962 +version:2.1.0-preview2-15744 +commithash:9e15cb6062ab5b9790d3fa699e018543a6950713 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json b/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json new file mode 100644 index 0000000000..583baf7a3a --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json @@ -0,0 +1,828 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.Server.HttpSys, Version=2.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Hosting.WebHostBuilderHttpSysExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseHttpSys", + "Parameters": [ + { + "Name": "hostBuilder", + "Type": "Microsoft.AspNetCore.Hosting.IWebHostBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHostBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "UseHttpSys", + "Parameters": [ + { + "Name": "hostBuilder", + "Type": "Microsoft.AspNetCore.Hosting.IWebHostBuilder" + }, + { + "Name": "options", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Hosting.IWebHostBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.AuthenticationManager", + "Visibility": "Public", + "Kind": "Class", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Schemes", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Schemes", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_AllowAnonymous", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_AllowAnonymous", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "None", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Basic", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "NTLM", + "Parameters": [], + "GenericParameter": [], + "Literal": "4" + }, + { + "Kind": "Field", + "Name": "Negotiate", + "Parameters": [], + "GenericParameter": [], + "Literal": "8" + }, + { + "Kind": "Field", + "Name": "Kerberos", + "Parameters": [], + "GenericParameter": [], + "Literal": "16" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.HttpSysDefaults", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "AuthenticationScheme", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.HttpSysException", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "System.ComponentModel.Win32Exception", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_ErrorCode", + "Parameters": [], + "ReturnType": "System.Int32", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.HttpSysOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_MaxAccepts", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MaxAccepts", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_EnableResponseCaching", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_EnableResponseCaching", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_UrlPrefixes", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefixCollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Authentication", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Server.HttpSys.AuthenticationManager", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Timeouts", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Server.HttpSys.TimeoutManager", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ThrowWriteExceptions", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ThrowWriteExceptions", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_MaxConnections", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MaxConnections", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RequestQueueLimit", + "Parameters": [], + "ReturnType": "System.Int64", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_RequestQueueLimit", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int64" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_MaxRequestBodySize", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MaxRequestBodySize", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_AllowSynchronousIO", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_AllowSynchronousIO", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.TimeoutManager", + "Visibility": "Public", + "Kind": "Class", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_EntityBody", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_EntityBody", + "Parameters": [ + { + "Name": "value", + "Type": "System.TimeSpan" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_DrainEntityBody", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_DrainEntityBody", + "Parameters": [ + { + "Name": "value", + "Type": "System.TimeSpan" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RequestQueue", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_RequestQueue", + "Parameters": [ + { + "Name": "value", + "Type": "System.TimeSpan" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_IdleConnection", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_IdleConnection", + "Parameters": [ + { + "Name": "value", + "Type": "System.TimeSpan" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_HeaderWait", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_HeaderWait", + "Parameters": [ + { + "Name": "value", + "Type": "System.TimeSpan" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_MinSendBytesPerSecond", + "Parameters": [], + "ReturnType": "System.Int64", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MinSendBytesPerSecond", + "Parameters": [ + { + "Name": "value", + "Type": "System.Int64" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefix", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Create", + "Parameters": [ + { + "Name": "scheme", + "Type": "System.String" + }, + { + "Name": "host", + "Type": "System.String" + }, + { + "Name": "port", + "Type": "System.String" + }, + { + "Name": "path", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefix", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Create", + "Parameters": [ + { + "Name": "scheme", + "Type": "System.String" + }, + { + "Name": "host", + "Type": "System.String" + }, + { + "Name": "portValue", + "Type": "System.Nullable" + }, + { + "Name": "path", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefix", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Create", + "Parameters": [ + { + "Name": "prefix", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefix", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_IsHttps", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Scheme", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Host", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Port", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_PortValue", + "Parameters": [], + "ReturnType": "System.Int32", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Path", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_FullPrefix", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Equals", + "Parameters": [ + { + "Name": "obj", + "Type": "System.Object" + } + ], + "ReturnType": "System.Boolean", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetHashCode", + "Parameters": [], + "ReturnType": "System.Int32", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ToString", + "Parameters": [], + "ReturnType": "System.String", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefixCollection", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "System.Collections.Generic.ICollection" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_Count", + "Parameters": [], + "ReturnType": "System.Int32", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_IsReadOnly", + "Parameters": [], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "prefix", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Add", + "Parameters": [ + { + "Name": "item", + "Type": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefix" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Clear", + "Parameters": [], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Contains", + "Parameters": [ + { + "Name": "item", + "Type": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefix" + } + ], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CopyTo", + "Parameters": [ + { + "Name": "array", + "Type": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefix[]" + }, + { + "Name": "arrayIndex", + "Type": "System.Int32" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Remove", + "Parameters": [ + { + "Name": "prefix", + "Type": "System.String" + } + ], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Remove", + "Parameters": [ + { + "Name": "item", + "Type": "Microsoft.AspNetCore.Server.HttpSys.UrlPrefix" + } + ], + "ReturnType": "System.Boolean", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetEnumerator", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerator", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.IEnumerable", + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file From bca8042fe0d2d46587e75d4987fe5ee6289d9972 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 25 Mar 2018 15:40:37 -0700 Subject: [PATCH 575/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 22 +++++++++++----------- korebuild-lock.txt | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 5aaa28edec..25f3879d2c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15728 - 2.1.0-preview2-30301 - 2.1.0-preview2-30301 - 2.1.0-preview2-30301 - 2.1.0-preview2-30301 + 2.1.0-preview3-17001 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 + 2.1.0-preview3-32037 2.0.0 - 2.1.0-preview2-26308-01 - 2.1.0-preview2-30301 - 15.6.0 - 4.5.0-preview2-26308-02 - 4.5.0-preview2-26308-02 - 4.5.0-preview2-26308-02 + 2.1.0-preview2-26314-02 + 2.1.0-preview3-32037 + 15.6.1 + 4.5.0-preview2-26313-01 + 4.5.0-preview2-26313-01 + 4.5.0-preview2-26313-01 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 138d848db1..3a326c7d58 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15728 -commithash:393377068ddcf51dfee0536536d455f57a828b06 +version:2.1.0-preview3-17001 +commithash:dda68c56abf0d3b911fe6a2315872c446b314585 From 5a65e8ce93e8faeb9d447fa68d628457ed47c954 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Wed, 28 Mar 2018 10:46:44 -0700 Subject: [PATCH 576/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 22 +++++++++++----------- korebuild-lock.txt | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index d779b90b03..531a39e4b3 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview2-15744 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 - 2.1.0-preview2-30355 + 2.1.0-preview2-15749 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 + 2.1.0-preview2-30478 2.0.0 - 2.1.0-preview2-26314-02 - 2.1.0-preview2-30355 - 15.6.0 - 4.5.0-preview2-26313-01 - 4.5.0-preview2-26313-01 - 4.5.0-preview2-26313-01 + 2.1.0-preview2-26326-03 + 2.1.0-preview2-30478 + 15.6.1 + 4.5.0-preview2-26326-04 + 4.5.0-preview2-26326-04 + 4.5.0-preview2-26326-04 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index f531e7b0f7..b8e036fe2c 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview2-15744 -commithash:9e15cb6062ab5b9790d3fa699e018543a6950713 +version:2.1.0-preview2-15749 +commithash:5544c9ab20fa5e24b9e155d8958a3c3b6f5f9df9 From 988972e1e5c920e199b4ede7dff5f867b502234d Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Thu, 29 Mar 2018 09:06:27 -0700 Subject: [PATCH 577/597] Disable regressed negotiate test #439 --- .../AuthenticationTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index 7a4a184087..b1fdb0ed19 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -353,7 +353,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] + [ConditionalTheory(Skip = "https://github.com/aspnet/HttpSysServer/issues/439")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented From adbbbcf4deed896f8a828c46ea5ff932b532dd57 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Fri, 30 Mar 2018 09:24:31 -0700 Subject: [PATCH 578/597] Disable regressed negotiate test #439 --- .../AuthenticationTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index 7a4a184087..b1fdb0ed19 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -353,7 +353,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory] + [ConditionalTheory(Skip = "https://github.com/aspnet/HttpSysServer/issues/439")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented From 738522049a0fb6f89c5c100ad98ff85dc53f8422 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 3 Apr 2018 22:27:56 +0000 Subject: [PATCH 579/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 20 ++++++++++---------- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 25f3879d2c..3d57165b97 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17001 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 - 2.1.0-preview3-32037 + 2.1.0-preview3-17002 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 + 2.1.0-preview3-32110 2.0.0 - 2.1.0-preview2-26314-02 - 2.1.0-preview3-32037 + 2.1.0-preview3-26331-01 + 2.1.0-preview3-32110 15.6.1 - 4.5.0-preview2-26313-01 - 4.5.0-preview2-26313-01 - 4.5.0-preview2-26313-01 + 4.5.0-preview3-26331-02 + 4.5.0-preview3-26331-02 + 4.5.0-preview3-26331-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3a326c7d58..b3af0b8bce 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17001 -commithash:dda68c56abf0d3b911fe6a2315872c446b314585 +version:2.1.0-preview3-17002 +commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f From d9c823d3b00ca614d497faa6a33ccc4846a2ec34 Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Wed, 4 Apr 2018 15:36:44 -0700 Subject: [PATCH 580/597] Renable auth tests with new HttpClient #439, ServerTests/#82 --- build/dependencies.props | 18 +++++++++--------- .../AuthenticationTests.cs | 19 +++++++------------ .../Listener/AuthenticationTests.cs | 8 +++----- 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3d57165b97..89f628ce25 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,17 +4,17 @@ 2.1.0-preview3-17002 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 - 2.1.0-preview3-32110 + 2.1.0-preview3-32122 + 2.1.0-preview3-32122 + 2.1.0-preview3-32122 + 2.1.0-preview3-32122 2.0.0 - 2.1.0-preview3-26331-01 - 2.1.0-preview3-32110 + 2.1.0-preview2-26403-06 + 2.1.0-preview3-32122 15.6.1 - 4.5.0-preview3-26331-02 - 4.5.0-preview3-26331-02 - 4.5.0-preview3-26331-02 + 4.5.0-preview2-26403-05 + 4.5.0-preview2-26403-05 + 4.5.0-preview2-26403-05 2.3.1 2.4.0-beta.1.build3945 diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs index b1fdb0ed19..06bc6f2c32 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs @@ -40,9 +40,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Empty(response.Headers.WwwAuthenticate); } } - +#if !NETCOREAPP2_0 + // https://github.com/aspnet/ServerTests/issues/82 [ConditionalTheory] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -61,7 +61,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalTheory] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -84,7 +83,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; @@ -109,7 +107,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal("Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } } - +#endif [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] @@ -240,9 +238,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } - +#if !NETCOREAPP2_0 + // https://github.com/aspnet/ServerTests/issues/82 [ConditionalTheory] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -266,7 +264,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalTheory] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -290,7 +287,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task AuthTypes_OneChallengeSent() { var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; @@ -309,7 +305,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys } [ConditionalTheory] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] @@ -334,7 +329,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count); } } - +#endif [ConditionalFact] public async Task AuthTypes_Forbid_Forbidden() { @@ -353,7 +348,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - [ConditionalTheory(Skip = "https://github.com/aspnet/HttpSysServer/issues/439")] + [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // Not implemented diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs index ac7cb7056e..db32323bdf 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs @@ -40,9 +40,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Empty(response.Headers.WwwAuthenticate); } } - +#if !NETCOREAPP2_0 + // https://github.com/aspnet/ServerTests/issues/82 [ConditionalTheory] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationType.Digest)] // TODO: Not implemented @@ -62,7 +62,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } [ConditionalTheory] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] // [InlineData(AuthenticationSchemes.Digest)] // TODO: Not implemented @@ -88,7 +87,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded() { string address; @@ -113,7 +111,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.Equal("Negotiate, NTLM, basic", response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase); } } - +#endif [ConditionalTheory] [InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.NTLM)] From 61f7c82d49eeb11b057eeaaafc1cc49ae494affa Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 10 Apr 2018 17:57:25 +0200 Subject: [PATCH 581/597] Replace Helpers.CompletedTask and Helpers.CanceledTask (#446) --- src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs | 12 ------------ .../RequestProcessing/RequestStream.cs | 2 +- .../RequestProcessing/ResponseBody.cs | 14 +++++++------- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs b/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs index 9fee1c191a..5376203319 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs @@ -14,18 +14,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal static readonly byte[] ChunkTerminator = new byte[] { (byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }; internal static readonly byte[] CRLF = new byte[] { (byte)'\r', (byte)'\n' }; - internal static Task CompletedTask() - { - return Task.FromResult(null); - } - - internal static Task CanceledTask() - { - TaskCompletionSource tcs = new TaskCompletionSource(); - tcs.TrySetCanceled(); - return tcs.Task; - } - internal static ConfiguredTaskAwaitable SupressContext(this Task task) { return task.ConfigureAwait(continueOnCapturedContext: false); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index 6e0cb2ace5..f0bf45d68f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -306,7 +306,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (cancellationToken.IsCancellationRequested) { - return Helpers.CanceledTask(); + return Task.FromCanceled(cancellationToken); } // TODO: Verbose log parameters diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs index 87ae976cbd..8f6341db63 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs @@ -264,7 +264,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (_disposed) { - return Helpers.CompletedTask(); + return Task.CompletedTask; } return FlushInternalAsync(new ArraySegment(), cancellationToken); } @@ -274,20 +274,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (_skipWrites) { - return Helpers.CompletedTask(); + return Task.CompletedTask; } var started = _requestContext.Response.HasStarted; if (data.Count == 0 && started) { // No data to send and we've already sent the headers - return Helpers.CompletedTask(); + return Task.CompletedTask; } if (cancellationToken.IsCancellationRequested) { Abort(ThrowWriteExceptions); - return Helpers.CanceledTask(); + return Task.FromCanceled(cancellationToken); } // Make sure all validation is performed before this computes the headers @@ -535,20 +535,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys { if (_skipWrites) { - return Helpers.CompletedTask(); + return Task.CompletedTask; } var started = _requestContext.Response.HasStarted; if (count == 0 && started) { // No data to send and we've already sent the headers - return Helpers.CompletedTask(); + return Task.CompletedTask; } if (cancellationToken.IsCancellationRequested) { Abort(ThrowWriteExceptions); - return Helpers.CanceledTask(); + return Task.FromCanceled(cancellationToken); } // We are setting buffer size to 1 to prevent FileStream from allocating it's internal buffer From bec259f976efa3def5a28019b0b4a0b24ab8523e Mon Sep 17 00:00:00 2001 From: FabianMeiswinkel Date: Tue, 10 Apr 2018 12:08:33 -0700 Subject: [PATCH 582/597] #364 - Expose HTTP_503_RESPONSE_VERBOSITY option (#447) --- .../Http503VerbosityLevel .cs | 26 ++++++++++++ .../HttpSysOptions.cs | 40 +++++++++++++++++++ .../NativeInterop/RequestQueue.cs | 15 +++++++ .../Listener/ServerTests.cs | 16 ++++++++ .../ServerTests.cs | 39 ++++++++++++++++++ 5 files changed, 136 insertions(+) create mode 100644 src/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs b/src/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs new file mode 100644 index 0000000000..09da208c09 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Server.HttpSys +{ + /// + /// Enum declaring the allowed values for the verbosity level when http.sys reject requests due to throttling. + /// + public enum Http503VerbosityLevel : long + { + /// + /// A 503 response is not sent; the connection is reset. This is the default HTTP Server API behavior. + /// + Basic = 0, + + /// + /// The HTTP Server API sends a 503 response with a "Service Unavailable" reason phrase. + /// + Limited = 1, + + /// + /// The HTTP Server API sends a 503 response with a detailed reason phrase. + /// + Full = 2 + } +} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs index cf34e6e368..93d6e2dd82 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs @@ -2,18 +2,21 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Globalization; using Microsoft.AspNetCore.Http.Features; namespace Microsoft.AspNetCore.Server.HttpSys { public class HttpSysOptions { + private const Http503VerbosityLevel DefaultRejectionVerbosityLevel = Http503VerbosityLevel.Basic; // Http.sys default. private const long DefaultRequestQueueLength = 1000; // Http.sys default. internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount; // Matches the default maxAllowedContentLength in IIS (~28.6 MB) // https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005 private const long DefaultMaxRequestBodySize = 30000000; + private Http503VerbosityLevel _rejectionVebosityLevel = DefaultRejectionVerbosityLevel; // The native request queue private long _requestQueueLength = DefaultRequestQueueLength; private long? _maxConnections; @@ -137,6 +140,38 @@ namespace Microsoft.AspNetCore.Server.HttpSys /// public bool AllowSynchronousIO { get; set; } = true; + /// + /// Gets or sets a value that controls how http.sys reacts when rejecting requests due to throttling conditions - like when the request + /// queue limit is reached. The default in http.sys is "Basic" which means http.sys is just resetting the TCP connection. IIS uses Limited + /// as its default behavior which will result in sending back a 503 - Service Unavailable back to the client. + /// + public Http503VerbosityLevel Http503Verbosity + { + get + { + return _rejectionVebosityLevel; + } + set + { + if (value < Http503VerbosityLevel.Basic || value > Http503VerbosityLevel.Full) + { + string message = String.Format( + CultureInfo.InvariantCulture, + "The value must be one of the values defined in the '{0}' enum.", + typeof(Http503VerbosityLevel).Name); + + throw new ArgumentOutOfRangeException(nameof(value), value, message); + } + + if (_requestQueue != null) + { + _requestQueue.SetRejectionVerbosity(value); + } + // Only store it if it succeeds or hasn't started yet + _rejectionVebosityLevel = value; + } + } + internal void Apply(UrlGroup urlGroup, RequestQueue requestQueue) { _urlGroup = urlGroup; @@ -152,6 +187,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys _requestQueue.SetLengthLimit(_requestQueueLength); } + if (_rejectionVebosityLevel != DefaultRejectionVerbosityLevel) + { + _requestQueue.SetRejectionVerbosity(_rejectionVebosityLevel); + } + Authentication.SetUrlGroupSecurity(urlGroup); Timeouts.SetUrlGroupTimeouts(urlGroup); } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs index 29f43b6fd5..1d3546f91b 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs @@ -99,6 +99,21 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + // The listener must be active for this to work. + internal unsafe void SetRejectionVerbosity(Http503VerbosityLevel verbosity) + { + CheckDisposed(); + + var result = HttpApi.HttpSetRequestQueueProperty(Handle, + HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServer503VerbosityProperty, + new IntPtr((void*)&verbosity), (uint)Marshal.SizeOf(), 0, IntPtr.Zero); + + if (result != 0) + { + throw new HttpSysException((int)result); + } + } + public void Dispose() { if (_disposed) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index c15d47fd15..e70e3de1ac 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -245,6 +245,22 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener } } + [ConditionalFact] + public async Task Server_SetRejectionVerbosityLevel_Success() + { + using (var server = Utilities.CreateHttpServer(out string address)) + { + server.Options.Http503Verbosity = Http503VerbosityLevel.Limited; + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(Utilities.DefaultTimeout); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(string.Empty, response); + } + } + [ConditionalFact] public async Task Server_HotAddPrefix_Success() { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs index 4a451bd110..e0ecbc7d2b 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Text; @@ -298,6 +299,44 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + [ConditionalFact] + public async Task Server_SetHttp503VebosittHittingThrottle_Success() + { + // This is just to get a dynamic port + string address; + using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } + + var server = Utilities.CreatePump(); + server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address)); + Assert.Null(server.Listener.Options.MaxConnections); + server.Listener.Options.MaxConnections = 3; + server.Listener.Options.Http503Verbosity = Http503VerbosityLevel.Limited; + + using (server) + { + await server.StartAsync(new DummyApplication(), CancellationToken.None); + + using (var client1 = await SendHungRequestAsync("GET", address)) + using (var client2 = await SendHungRequestAsync("GET", address)) + { + using (var client3 = await SendHungRequestAsync("GET", address)) + { + using (HttpClient client4 = new HttpClient()) + { + // Maxed out, refuses connection should return 503 + HttpResponseMessage response = await client4.GetAsync(address); + + Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode); + } + } + + // A connection has been closed, try again. + string responseText = await SendRequestAsync(address); + Assert.Equal(string.Empty, responseText); + } + } + } + [ConditionalFact] public void Server_SetConnectionLimitArgumentValidation_Success() { From 8b5053957efce4a79fa5bceeaed311d37bc7dc6e Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 15 Apr 2018 14:11:07 -0700 Subject: [PATCH 583/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 20 ++++++++++---------- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 89f628ce25..74e50cc8eb 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,18 +3,18 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17002 - 2.1.0-preview3-32122 - 2.1.0-preview3-32122 - 2.1.0-preview3-32122 - 2.1.0-preview3-32122 + 2.1.0-preview3-17018 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 + 2.1.0-preview3-32233 2.0.0 - 2.1.0-preview2-26403-06 - 2.1.0-preview3-32122 + 2.1.0-preview3-26413-05 + 2.1.0-preview3-32233 15.6.1 - 4.5.0-preview2-26403-05 - 4.5.0-preview2-26403-05 - 4.5.0-preview2-26403-05 + 4.5.0-preview3-26413-02 + 4.5.0-preview3-26413-02 + 4.5.0-preview3-26413-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b3af0b8bce..b419d767b9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17002 -commithash:b8e4e6ab104adc94c0719bb74229870e9b584a7f +version:2.1.0-preview3-17018 +commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be From 6ce8b74ea4a59a33e3a5c08bf45f86a2456da64b Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Mon, 16 Apr 2018 16:58:04 -0700 Subject: [PATCH 584/597] Branching for 2.1.0-rc1 --- build/repo.props | 3 ++- korebuild.json | 4 ++-- version.props | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/repo.props b/build/repo.props index 78b0ce5879..dab1601c88 100644 --- a/build/repo.props +++ b/build/repo.props @@ -1,9 +1,10 @@ - + Internal.AspNetCore.Universe.Lineup + 2.1.0-rc1-* https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json diff --git a/korebuild.json b/korebuild.json index bd5d51a51b..678d8bb948 100644 --- a/korebuild.json +++ b/korebuild.json @@ -1,4 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev" + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", + "channel": "release/2.1" } diff --git a/version.props b/version.props index 24f2b00a0a..e27532787e 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - preview3 + rc1 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From c07699a58b46ebb875e49bcb88f254012e155284 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 19 Apr 2018 16:39:38 -0700 Subject: [PATCH 585/597] Set NETStandardImplicitPackageVersion via dependencies.props --- Directory.Build.targets | 1 + build/dependencies.props | 1 + 2 files changed, 2 insertions(+) diff --git a/Directory.Build.targets b/Directory.Build.targets index 894b1d0cf8..53b3f6e1da 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -2,5 +2,6 @@ $(MicrosoftNETCoreApp20PackageVersion) $(MicrosoftNETCoreApp21PackageVersion) + $(NETStandardLibrary20PackageVersion) diff --git a/build/dependencies.props b/build/dependencies.props index 74e50cc8eb..0d083f32c9 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -12,6 +12,7 @@ 2.1.0-preview3-26413-05 2.1.0-preview3-32233 15.6.1 + 2.0.1 4.5.0-preview3-26413-02 4.5.0-preview3-26413-02 4.5.0-preview3-26413-02 From 4a4a1f4c2d62dca7de0d3ecd4d27c6d764400ce9 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Thu, 19 Apr 2018 22:22:43 -0700 Subject: [PATCH 586/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 20 ++++++++++---------- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 0d083f32c9..6dcbd42125 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,19 +3,19 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-preview3-17018 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 - 2.1.0-preview3-32233 + 2.1.0-rc1-15774 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 + 2.1.0-rc1-30613 2.0.0 - 2.1.0-preview3-26413-05 - 2.1.0-preview3-32233 + 2.1.0-rc1-26419-02 + 2.1.0-rc1-30613 15.6.1 + 4.5.0-rc1-26419-03 2.0.1 - 4.5.0-preview3-26413-02 - 4.5.0-preview3-26413-02 - 4.5.0-preview3-26413-02 + 4.5.0-rc1-26419-03 + 4.5.0-rc1-26419-03 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index b419d767b9..9d4ef8c888 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-preview3-17018 -commithash:af264ca131f212b5ba8aafbc5110fc0fc510a2be +version:2.1.0-rc1-15774 +commithash:ed5ca9de3c652347dbb0158a9a65eff3471d2114 From 3cb76608e4ea6d589e4a6bc5f9c2c2845da434a8 Mon Sep 17 00:00:00 2001 From: "Nate McMaster (automated)" Date: Mon, 30 Apr 2018 14:51:41 -0700 Subject: [PATCH 587/597] Bump version to 2.1.0-rtm --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index e27532787e..b9552451d8 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ 2.1.0 - rc1 + rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000 From 280bd9e9a466b0f02532c82640bc8c29bddb7f10 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Fri, 4 May 2018 07:36:15 -0700 Subject: [PATCH 588/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 22 +++++++++++----------- korebuild-lock.txt | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 6dcbd42125..6f71e2ed21 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,19 +3,19 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rc1-15774 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 - 2.1.0-rc1-30613 + 2.1.0-rtm-15783 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 + 2.1.0-rtm-30721 2.0.0 - 2.1.0-rc1-26419-02 - 2.1.0-rc1-30613 + 2.1.0-rtm-26502-02 + 2.1.0-rtm-30721 15.6.1 - 4.5.0-rc1-26419-03 - 2.0.1 - 4.5.0-rc1-26419-03 - 4.5.0-rc1-26419-03 + 4.5.0-rtm-26502-02 + 2.0.3 + 4.5.0-rtm-26502-02 + 4.5.0-rtm-26502-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 9d4ef8c888..3673744db9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-rc1-15774 -commithash:ed5ca9de3c652347dbb0158a9a65eff3471d2114 +version:2.1.0-rtm-15783 +commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 From 360be3692612eff565797887790ad8685c942555 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 29 May 2018 09:39:05 -0700 Subject: [PATCH 589/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 20 ++++++++++---------- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 6f71e2ed21..db7eceea06 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,19 +3,19 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.0-rtm-15783 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 - 2.1.0-rtm-30721 + 2.1.1-rtm-15790 + 2.1.0 + 2.1.0 + 2.1.0 + 2.1.0 2.0.0 - 2.1.0-rtm-26502-02 - 2.1.0-rtm-30721 + 2.1.0 + 2.1.0 15.6.1 - 4.5.0-rtm-26502-02 + 4.5.0 2.0.3 - 4.5.0-rtm-26502-02 - 4.5.0-rtm-26502-02 + 4.5.0 + 4.5.0 2.3.1 2.4.0-beta.1.build3945 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 3673744db9..cd5b409a1e 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.0-rtm-15783 -commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 +version:2.1.1-rtm-15790 +commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 From 5bc05b26de50fb93a9f79180ee9a039f4bc50b9f Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 5 Jun 2018 09:11:37 -0700 Subject: [PATCH 590/597] Bumping version from 2.1.0 to 2.1.1 --- version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.props b/version.props index b9552451d8..669c874829 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - + - 2.1.0 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From 2e4a9f8987389fd9342d952316a5d51cc6962f8b Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 12 Jun 2018 19:20:59 +0000 Subject: [PATCH 591/597] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 12 ++++++------ korebuild-lock.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index db7eceea06..f6aa48b007 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,14 +3,14 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 2.1.1-rtm-15790 - 2.1.0 - 2.1.0 + 2.1.1-rtm-15793 + 2.1.1 + 2.1.1 2.1.0 - 2.1.0 + 2.1.1 2.0.0 - 2.1.0 - 2.1.0 + 2.1.1 + 2.1.1 15.6.1 4.5.0 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index cd5b409a1e..bc84e0cd53 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15790 -commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 +version:2.1.1-rtm-15793 +commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a From 4b93b75e78407d56d4045000721bdbbd005b6010 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Thu, 14 Jun 2018 10:27:23 -0700 Subject: [PATCH 592/597] Set 2.1 baselines --- .../baseline.netcore.json | 77 ++++++++++++++++--- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json b/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json index 583baf7a3a..a2a3a393fa 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Server.HttpSys, Version=2.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Server.HttpSys, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Hosting.WebHostBuilderHttpSysExtensions", @@ -144,6 +144,38 @@ ], "GenericParameters": [] }, + { + "Name": "Microsoft.AspNetCore.Server.HttpSys.Http503VerbosityLevel", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "BaseType": "System.Int64", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "Basic", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "Limited", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + }, + { + "Kind": "Field", + "Name": "Full", + "Parameters": [], + "GenericParameter": [], + "Literal": "2" + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.Server.HttpSys.HttpSysDefaults", "Visibility": "Public", @@ -363,6 +395,27 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_Http503Verbosity", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Server.HttpSys.Http503VerbosityLevel", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Http503Verbosity", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Server.HttpSys.Http503VerbosityLevel" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Constructor", "Name": ".ctor", @@ -683,6 +736,17 @@ "System.Collections.Generic.ICollection" ], "Members": [ + { + "Kind": "Method", + "Name": "GetEnumerator", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerator", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "System.Collections.Generic.IEnumerable", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "get_Count", @@ -809,17 +873,6 @@ "ImplementedInterface": "System.Collections.Generic.ICollection", "Visibility": "Public", "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetEnumerator", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IEnumerator", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "System.Collections.Generic.IEnumerable", - "Visibility": "Public", - "GenericParameter": [] } ], "GenericParameters": [] From cbbe2975bcc1a8b1b44d0bd015d0b77a6c725c5a Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 27 Jun 2018 13:39:47 -0700 Subject: [PATCH 593/597] Bumping version from 2.1.1 to 2.1.2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 669c874829..478dfd16ed 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.1 + 2.1.2 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From 79bb7eb7a640c8b7e60947c388a214ef8381e27a Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 15:06:33 -0700 Subject: [PATCH 594/597] Reverting version from 2.1.2 back to 2.1.1 As a result of changing the way we apply servicing updates to aspnet core, this repo did not need the version bump because there are no planned product changes in this repo. --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 478dfd16ed..669c874829 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.2 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From 69cfae919cc03882430a599fa83e231eecd13d24 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 18:48:49 -0700 Subject: [PATCH 595/597] Updating dependencies to 2.1.2 and adding a section for pinned variable versions --- build/dependencies.props | 13 ++++++++++--- korebuild-lock.txt | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index f6aa48b007..d5238e801c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,14 +2,16 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - 2.1.1-rtm-15793 + + + + 2.1.3-rtm-15802 2.1.1 2.1.1 2.1.0 2.1.1 2.0.0 - 2.1.1 + 2.1.2 2.1.1 15.6.1 4.5.0 @@ -19,5 +21,10 @@ 2.3.1 2.4.0-beta.1.build3945 + + + + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index bc84e0cd53..251c227c83 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15793 -commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a +version:2.1.3-rtm-15802 +commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a From d8d1f36f28359b76f838a99e425b2af2565538f0 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 12 Jul 2018 11:53:51 -0700 Subject: [PATCH 596/597] Pin version variables to the ASP.NET Core 2.1.2 baseline This reverts our previous policy of cascading versions on all servicing updates. This moves variables into the 'pinned' section, and points them to the latest stable release (versions that were used at the time of the 2.1.2 release). --- build/dependencies.props | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index d5238e801c..0a90c83355 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,15 +4,10 @@ - + 2.1.3-rtm-15802 - 2.1.1 - 2.1.1 - 2.1.0 - 2.1.1 2.0.0 2.1.2 - 2.1.1 15.6.1 4.5.0 2.0.3 @@ -26,5 +21,11 @@ - - + + 2.1.1 + 2.1.1 + 2.1.0 + 2.1.1 + 2.1.1 + + \ No newline at end of file From 03db4faa688e8a0ae0e9d7a379014edaf171673e Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 21 Nov 2018 15:05:23 -0800 Subject: [PATCH 597/597] Reorganize source code in preparation to move into aspnet/AspNetCore Prior to reorganization, this source code was found in https://github.com/aspnet/HttpSysServer/tree/d8d1f36f28359b76f838a99e425b2af2565538f0 --- .appveyor.yml | 17 -- .gitattributes | 51 ---- .travis.yml | 27 -- CONTRIBUTING.md | 4 - LICENSE.txt | 14 -- NuGet.config | 7 - build.cmd | 2 - build.sh | 8 - korebuild-lock.txt | 2 - korebuild.json | 4 - run.cmd | 2 - run.ps1 | 196 --------------- run.sh | 231 ------------------ .gitignore => src/HttpSysServer/.gitignore | 0 .../HttpSysServer/Directory.Build.props | 0 .../HttpSysServer/Directory.Build.targets | 0 .../HttpSysServer/HttpSysServer.sln | 0 .../HttpSysServer/NuGetPackageVerifier.json | 0 README.md => src/HttpSysServer/README.md | 0 {build => src/HttpSysServer/build}/Key.snk | Bin .../HttpSysServer/build}/dependencies.props | 0 {build => src/HttpSysServer/build}/repo.props | 0 .../HttpSysServer/build}/sources.props | 0 .../samples}/HotAddSample/HotAddSample.csproj | 0 .../Properties/launchSettings.json | 0 .../samples}/HotAddSample/Startup.cs | 0 .../samples}/SelfHostServer/App.config | 0 .../Properties/launchSettings.json | 0 .../samples}/SelfHostServer/Public/1kb.txt | 0 .../SelfHostServer/SelfHostServer.csproj | 0 .../samples}/SelfHostServer/Startup.cs | 0 .../samples}/TestClient/App.config | 0 .../samples}/TestClient/Program.cs | 0 .../TestClient/Properties/AssemblyInfo.cs | 0 .../samples}/TestClient/TestClient.csproj | 0 .../Constants.cs | 0 .../NativeInterop/CookedUrl.cs | 0 .../NativeInterop/HeapAllocHandle.cs | 0 .../NativeInterop/HttpApiTypes.cs | 0 .../NativeInterop/HttpSysRequestHeader.cs | 0 .../NativeInterop/HttpSysResponseHeader.cs | 0 .../NativeInterop/NclUtilities.cs | 0 .../SafeLocalFreeChannelBinding.cs | 0 .../NativeInterop/SafeLocalMemHandle.cs | 0 .../NativeInterop/SafeNativeOverlapped.cs | 0 .../NativeInterop/SocketAddress.cs | 0 .../NativeInterop/UnsafeNativeMethods.cs | 0 .../RequestProcessing/HeaderCollection.cs | 0 .../RequestProcessing/HeaderEncoding.cs | 0 .../RequestProcessing/HeaderParser.cs | 0 .../RequestProcessing/HttpKnownHeaderNames.cs | 0 .../RequestProcessing/NativeRequestContext.cs | 0 .../RequestProcessing/RawUrlHelper.cs | 0 .../RequestHeaders.Generated.cs | 0 .../RequestProcessing/RequestHeaders.cs | 0 .../RequestProcessing/RequestUriBuilder.cs | 0 .../RequestProcessing/SslStatus.cs | 0 .../src}/Directory.Build.props | 0 .../AsyncAcceptContext.cs | 0 .../AuthenticationHandler.cs | 0 .../AuthenticationManager.cs | 0 .../AuthenticationSchemes.cs | 0 .../FeatureContext.cs | 0 .../Helpers.cs | 0 .../Http503VerbosityLevel .cs | 0 .../HttpSysDefaults.cs | 0 .../HttpSysException.cs | 0 .../HttpSysListener.cs | 0 .../HttpSysOptions.cs | 0 .../LogHelper.cs | 0 .../MessagePump.cs | 0 ...Microsoft.AspNetCore.Server.HttpSys.csproj | 0 .../NativeInterop/ComNetOS.cs | 0 .../NativeInterop/DisconnectListener.cs | 0 .../NativeInterop/HttpApi.cs | 0 .../NativeInterop/HttpRequestQueueV2Handle.cs | 0 .../NativeInterop/HttpServerSessionHandle.cs | 0 .../NativeInterop/HttpSysSettings.cs | 0 .../NativeInterop/IntPtrHelper.cs | 0 .../NativeInterop/RequestQueue.cs | 0 .../NativeInterop/ServerSession.cs | 0 .../NativeInterop/TokenBindingUtil.cs | 0 .../NativeInterop/UrlGroup.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Properties/Resources.Designer.cs | 0 .../RequestProcessing/BoundaryType.cs | 0 .../RequestProcessing/ClientCertLoader.cs | 0 .../RequestProcessing/HttpReasonPhrase.cs | 0 .../RequestProcessing/OpaqueStream.cs | 0 .../RequestProcessing/Request.cs | 0 .../RequestProcessing/RequestContext.cs | 0 .../RequestHeaders.Generated.tt | 0 .../RequestProcessing/RequestStream.cs | 0 .../RequestStreamAsyncResult.cs | 0 .../RequestProcessing/Response.cs | 0 .../RequestProcessing/ResponseBody.cs | 0 .../ResponseStreamAsyncResult.cs | 0 .../Resources.resx | 0 .../ResponseStream.cs | 0 .../StandardFeatureCollection.cs | 0 .../TimeoutManager.cs | 0 .../UrlPrefix.cs | 0 .../UrlPrefixCollection.cs | 0 .../ValidationHelper.cs | 0 .../WebHostBuilderHttpSysExtensions.cs | 0 .../baseline.netcore.json | 0 .../HttpSysServer/test}/Directory.Build.props | 0 .../AuthenticationTests.cs | 0 .../DummyApplication.cs | 0 .../HttpsTests.cs | 0 .../Listener/AuthenticationTests.cs | 0 .../Listener/HttpsTests.cs | 0 .../Listener/OpaqueUpgradeTests.cs | 0 .../Listener/RequestBodyTests.cs | 0 .../Listener/RequestHeaderTests.cs | 0 .../Listener/RequestTests.cs | 0 .../Listener/ResponseBodyTests.cs | 0 .../Listener/ResponseCachingTests.cs | 0 .../Listener/ResponseHeaderTests.cs | 0 .../Listener/ResponseSendFileTests.cs | 0 .../Listener/ResponseTests.cs | 0 .../Listener/ServerTests.cs | 0 .../Listener/Utilities.cs | 0 .../MessagePumpTests.cs | 0 ...Core.Server.HttpSys.FunctionalTests.csproj | 0 .../OSDontSkipConditionAttribute.cs | 0 .../OpaqueUpgradeTests.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../RequestBodyLimitTests.cs | 0 .../RequestBodyTests.cs | 0 .../RequestHeaderTests.cs | 0 .../RequestTests.cs | 0 .../ResponseBodyTests.cs | 0 .../ResponseCachingTests.cs | 0 .../ResponseHeaderTests.cs | 0 .../ResponseSendFileTests.cs | 0 .../ResponseTests.cs | 0 .../ServerTests.cs | 0 .../Utilities.cs | 0 ...oft.AspNetCore.Server.HttpSys.Tests.csproj | 0 .../UrlPrefixTests.cs | 0 .../HttpSysServer/version.props | 0 142 files changed, 565 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 .gitattributes delete mode 100644 .travis.yml delete mode 100644 CONTRIBUTING.md delete mode 100644 LICENSE.txt delete mode 100644 NuGet.config delete mode 100644 build.cmd delete mode 100755 build.sh delete mode 100644 korebuild-lock.txt delete mode 100644 korebuild.json delete mode 100644 run.cmd delete mode 100644 run.ps1 delete mode 100755 run.sh rename .gitignore => src/HttpSysServer/.gitignore (100%) rename Directory.Build.props => src/HttpSysServer/Directory.Build.props (100%) rename Directory.Build.targets => src/HttpSysServer/Directory.Build.targets (100%) rename HttpSysServer.sln => src/HttpSysServer/HttpSysServer.sln (100%) rename NuGetPackageVerifier.json => src/HttpSysServer/NuGetPackageVerifier.json (100%) rename README.md => src/HttpSysServer/README.md (100%) rename {build => src/HttpSysServer/build}/Key.snk (100%) rename {build => src/HttpSysServer/build}/dependencies.props (100%) rename {build => src/HttpSysServer/build}/repo.props (100%) rename {build => src/HttpSysServer/build}/sources.props (100%) rename {samples => src/HttpSysServer/samples}/HotAddSample/HotAddSample.csproj (100%) rename {samples => src/HttpSysServer/samples}/HotAddSample/Properties/launchSettings.json (100%) rename {samples => src/HttpSysServer/samples}/HotAddSample/Startup.cs (100%) rename {samples => src/HttpSysServer/samples}/SelfHostServer/App.config (100%) rename {samples => src/HttpSysServer/samples}/SelfHostServer/Properties/launchSettings.json (100%) rename {samples => src/HttpSysServer/samples}/SelfHostServer/Public/1kb.txt (100%) rename {samples => src/HttpSysServer/samples}/SelfHostServer/SelfHostServer.csproj (100%) rename {samples => src/HttpSysServer/samples}/SelfHostServer/Startup.cs (100%) rename {samples => src/HttpSysServer/samples}/TestClient/App.config (100%) rename {samples => src/HttpSysServer/samples}/TestClient/Program.cs (100%) rename {samples => src/HttpSysServer/samples}/TestClient/Properties/AssemblyInfo.cs (100%) rename {samples => src/HttpSysServer/samples}/TestClient/TestClient.csproj (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs (100%) rename {shared => src/HttpSysServer/shared}/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs (100%) rename src/{ => HttpSysServer/src}/Directory.Build.props (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/AuthenticationSchemes.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/IntPtrHelper.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/BoundaryType.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpReasonPhrase.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.tt (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/Resources.resx (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/ValidationHelper.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs (100%) rename src/{ => HttpSysServer/src}/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json (100%) rename {test => src/HttpSysServer/test}/Directory.Build.props (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj (100%) rename {test => src/HttpSysServer/test}/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs (100%) rename version.props => src/HttpSysServer/version.props (100%) diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 4eea96ab69..0000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,17 +0,0 @@ -init: -- git config --global core.autocrlf true -branches: - only: - - dev - - /^release\/.*$/ - - /^(.*\/)?ci-.*$/ -build_script: -- ps: .\run.ps1 default-build -clone_depth: 1 -environment: - global: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -test: 'off' -deploy: 'off' -os: Visual Studio 2017 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 97b827b758..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,51 +0,0 @@ -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain - -*.jpg binary -*.png binary -*.gif binary - -*.cs text=auto diff=csharp -*.vb text=auto -*.resx text=auto -*.c text=auto -*.cpp text=auto -*.cxx text=auto -*.h text=auto -*.hxx text=auto -*.py text=auto -*.rb text=auto -*.java text=auto -*.html text=auto -*.htm text=auto -*.css text=auto -*.scss text=auto -*.sass text=auto -*.less text=auto -*.js text=auto -*.lisp text=auto -*.clj text=auto -*.sql text=auto -*.php text=auto -*.lua text=auto -*.m text=auto -*.asm text=auto -*.erl text=auto -*.fs text=auto -*.fsx text=auto -*.hs text=auto - -*.csproj text=auto -*.vbproj text=auto -*.fsproj text=auto -*.dbproj text=auto -*.sln text=auto eol=crlf -*.sh eol=lf diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 64bdbb4441..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: csharp -sudo: false -dist: trusty -env: - global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -mono: none -os: -- linux -- osx -osx_image: xcode8.2 -addons: - apt: - packages: - - libunwind8 -branches: - only: - - dev - - /^release\/.*$/ - - /^(.*\/)?ci-.*$/ -before_install: -- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s - /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib - /usr/local/lib/; fi -script: -- ./build.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 64ff041d5c..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,4 +0,0 @@ -Contributing -====== - -Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 7b2956ecee..0000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,14 +0,0 @@ -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed -under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. diff --git a/NuGet.config b/NuGet.config deleted file mode 100644 index e32bddfd51..0000000000 --- a/NuGet.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/build.cmd b/build.cmd deleted file mode 100644 index c0050bda12..0000000000 --- a/build.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.sh b/build.sh deleted file mode 100755 index 98a4b22765..0000000000 --- a/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) -chmod +x "$DIR/run.sh"; sync -"$DIR/run.sh" default-build "$@" diff --git a/korebuild-lock.txt b/korebuild-lock.txt deleted file mode 100644 index 251c227c83..0000000000 --- a/korebuild-lock.txt +++ /dev/null @@ -1,2 +0,0 @@ -version:2.1.3-rtm-15802 -commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a diff --git a/korebuild.json b/korebuild.json deleted file mode 100644 index 678d8bb948..0000000000 --- a/korebuild.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", - "channel": "release/2.1" -} diff --git a/run.cmd b/run.cmd deleted file mode 100644 index d52d5c7e68..0000000000 --- a/run.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/run.ps1 b/run.ps1 deleted file mode 100644 index 27dcf848f8..0000000000 --- a/run.ps1 +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env powershell -#requires -version 4 - -<# -.SYNOPSIS -Executes KoreBuild commands. - -.DESCRIPTION -Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. - -.PARAMETER Command -The KoreBuild command to run. - -.PARAMETER Path -The folder to build. Defaults to the folder containing this script. - -.PARAMETER Channel -The channel of KoreBuild to download. Overrides the value from the config file. - -.PARAMETER DotNetHome -The directory where .NET Core tools will be stored. - -.PARAMETER ToolsSource -The base url where build tools can be downloaded. Overrides the value from the config file. - -.PARAMETER Update -Updates KoreBuild to the latest version even if a lock file is present. - -.PARAMETER ConfigFile -The path to the configuration file that stores values. Defaults to korebuild.json. - -.PARAMETER ToolsSourceSuffix -The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. - -.PARAMETER Arguments -Arguments to be passed to the command - -.NOTES -This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. -When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. - -The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set -in the file are overridden by command line parameters. - -.EXAMPLE -Example config file: -```json -{ - "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", - "channel": "dev", - "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" -} -``` -#> -[CmdletBinding(PositionalBinding = $false)] -param( - [Parameter(Mandatory = $true, Position = 0)] - [string]$Command, - [string]$Path = $PSScriptRoot, - [Alias('c')] - [string]$Channel, - [Alias('d')] - [string]$DotNetHome, - [Alias('s')] - [string]$ToolsSource, - [Alias('u')] - [switch]$Update, - [string]$ConfigFile, - [string]$ToolsSourceSuffix, - [Parameter(ValueFromRemainingArguments = $true)] - [string[]]$Arguments -) - -Set-StrictMode -Version 2 -$ErrorActionPreference = 'Stop' - -# -# Functions -# - -function Get-KoreBuild { - - $lockFile = Join-Path $Path 'korebuild-lock.txt' - - if (!(Test-Path $lockFile) -or $Update) { - Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix - } - - $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 - if (!$version) { - Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" - } - $version = $version.TrimStart('version:').Trim() - $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) - - if (!(Test-Path $korebuildPath)) { - Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" - New-Item -ItemType Directory -Path $korebuildPath | Out-Null - $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" - - try { - $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" - Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix - if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { - # Use built-in commands where possible as they are cross-plat compatible - Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath - } - else { - # Fallback to old approach for old installations of PowerShell - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) - } - } - catch { - Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore - throw - } - finally { - Remove-Item $tmpfile -ErrorAction Ignore - } - } - - return $korebuildPath -} - -function Join-Paths([string]$path, [string[]]$childPaths) { - $childPaths | ForEach-Object { $path = Join-Path $path $_ } - return $path -} - -function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { - if ($RemotePath -notlike 'http*') { - Copy-Item $RemotePath $LocalPath - return - } - - $retries = 10 - while ($retries -gt 0) { - $retries -= 1 - try { - Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath - return - } - catch { - Write-Verbose "Request failed. $retries retries remaining" - } - } - - Write-Error "Download failed: '$RemotePath'." -} - -# -# Main -# - -# Load configuration or set defaults - -$Path = Resolve-Path $Path -if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } - -if (Test-Path $ConfigFile) { - try { - $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json - if ($config) { - if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } - if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} - } - } - catch { - Write-Warning "$ConfigFile could not be read. Its settings will be ignored." - Write-Warning $Error[0] - } -} - -if (!$DotNetHome) { - $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` - elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` - elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` - else { Join-Path $PSScriptRoot '.dotnet'} -} - -if (!$Channel) { $Channel = 'dev' } -if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } - -# Execute - -$korebuildPath = Get-KoreBuild -Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') - -try { - Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile - Invoke-KoreBuildCommand $Command @Arguments -} -finally { - Remove-Module 'KoreBuild' -ErrorAction Ignore -} diff --git a/run.sh b/run.sh deleted file mode 100755 index 834961fc3a..0000000000 --- a/run.sh +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# -# variables -# - -RESET="\033[0m" -RED="\033[0;31m" -YELLOW="\033[0;33m" -MAGENTA="\033[0;95m" -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" -verbose=false -update=false -repo_path="$DIR" -channel='' -tools_source='' -tools_source_suffix='' - -# -# Functions -# -__usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" - echo "" - echo "Arguments:" - echo " command The command to be run." - echo " ... Arguments passed to the command. Variable number of arguments allowed." - echo "" - echo "Options:" - echo " --verbose Show verbose output." - echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." - echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." - echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." - echo " --path The directory to build. Defaults to the directory containing the script." - echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." - echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." - echo " -u|--update Update to the latest KoreBuild even if the lock file is present." - echo "" - echo "Description:" - echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." - echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." - - if [[ "${1:-}" != '--no-exit' ]]; then - exit 2 - fi -} - -get_korebuild() { - local version - local lock_file="$repo_path/korebuild-lock.txt" - if [ ! -f "$lock_file" ] || [ "$update" = true ]; then - __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" - fi - version="$(grep 'version:*' -m 1 "$lock_file")" - if [[ "$version" == '' ]]; then - __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" - return 1 - fi - version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" - - { - if [ ! -d "$korebuild_path" ]; then - mkdir -p "$korebuild_path" - local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" - tmpfile="$(mktemp)" - echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" - if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then - unzip -q -d "$korebuild_path" "$tmpfile" - fi - rm "$tmpfile" || true - fi - - source "$korebuild_path/KoreBuild.sh" - } || { - if [ -d "$korebuild_path" ]; then - echo "Cleaning up after failed installation" - rm -rf "$korebuild_path" || true - fi - return 1 - } -} - -__error() { - echo -e "${RED}error: $*${RESET}" 1>&2 -} - -__warn() { - echo -e "${YELLOW}warning: $*${RESET}" -} - -__machine_has() { - hash "$1" > /dev/null 2>&1 - return $? -} - -__get_remote_file() { - local remote_path=$1 - local local_path=$2 - local remote_path_suffix=$3 - - if [[ "$remote_path" != 'http'* ]]; then - cp "$remote_path" "$local_path" - return 0 - fi - - local failed=false - if __machine_has wget; then - wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true - else - failed=true - fi - - if [ "$failed" = true ] && __machine_has curl; then - failed=false - curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true - fi - - if [ "$failed" = true ]; then - __error "Download failed: $remote_path" 1>&2 - return 1 - fi -} - -# -# main -# - -command="${1:-}" -shift - -while [[ $# -gt 0 ]]; do - case $1 in - -\?|-h|--help) - __usage --no-exit - exit 0 - ;; - -c|--channel|-Channel) - shift - channel="${1:-}" - [ -z "$channel" ] && __usage - ;; - --config-file|-ConfigFile) - shift - config_file="${1:-}" - [ -z "$config_file" ] && __usage - if [ ! -f "$config_file" ]; then - __error "Invalid value for --config-file. $config_file does not exist." - exit 1 - fi - ;; - -d|--dotnet-home|-DotNetHome) - shift - DOTNET_HOME="${1:-}" - [ -z "$DOTNET_HOME" ] && __usage - ;; - --path|-Path) - shift - repo_path="${1:-}" - [ -z "$repo_path" ] && __usage - ;; - -s|--tools-source|-ToolsSource) - shift - tools_source="${1:-}" - [ -z "$tools_source" ] && __usage - ;; - --tools-source-suffix|-ToolsSourceSuffix) - shift - tools_source_suffix="${1:-}" - [ -z "$tools_source_suffix" ] && __usage - ;; - -u|--update|-Update) - update=true - ;; - --verbose|-Verbose) - verbose=true - ;; - --) - shift - break - ;; - *) - break - ;; - esac - shift -done - -if ! __machine_has unzip; then - __error 'Missing required command: unzip' - exit 1 -fi - -if ! __machine_has curl && ! __machine_has wget; then - __error 'Missing required command. Either wget or curl is required.' - exit 1 -fi - -[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" -if [ -f "$config_file" ]; then - if __machine_has jq ; then - if jq '.' "$config_file" >/dev/null ; then - config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" - config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" - else - __warn "$config_file is invalid JSON. Its settings will be ignored." - fi - elif __machine_has python ; then - if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then - config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" - config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" - else - __warn "$config_file is invalid JSON. Its settings will be ignored." - fi - else - __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' - fi - - [ ! -z "${config_channel:-}" ] && channel="$config_channel" - [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" -fi - -[ -z "$channel" ] && channel='dev' -[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' - -get_korebuild -set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" -invoke_korebuild_command "$command" "$@" diff --git a/.gitignore b/src/HttpSysServer/.gitignore similarity index 100% rename from .gitignore rename to src/HttpSysServer/.gitignore diff --git a/Directory.Build.props b/src/HttpSysServer/Directory.Build.props similarity index 100% rename from Directory.Build.props rename to src/HttpSysServer/Directory.Build.props diff --git a/Directory.Build.targets b/src/HttpSysServer/Directory.Build.targets similarity index 100% rename from Directory.Build.targets rename to src/HttpSysServer/Directory.Build.targets diff --git a/HttpSysServer.sln b/src/HttpSysServer/HttpSysServer.sln similarity index 100% rename from HttpSysServer.sln rename to src/HttpSysServer/HttpSysServer.sln diff --git a/NuGetPackageVerifier.json b/src/HttpSysServer/NuGetPackageVerifier.json similarity index 100% rename from NuGetPackageVerifier.json rename to src/HttpSysServer/NuGetPackageVerifier.json diff --git a/README.md b/src/HttpSysServer/README.md similarity index 100% rename from README.md rename to src/HttpSysServer/README.md diff --git a/build/Key.snk b/src/HttpSysServer/build/Key.snk similarity index 100% rename from build/Key.snk rename to src/HttpSysServer/build/Key.snk diff --git a/build/dependencies.props b/src/HttpSysServer/build/dependencies.props similarity index 100% rename from build/dependencies.props rename to src/HttpSysServer/build/dependencies.props diff --git a/build/repo.props b/src/HttpSysServer/build/repo.props similarity index 100% rename from build/repo.props rename to src/HttpSysServer/build/repo.props diff --git a/build/sources.props b/src/HttpSysServer/build/sources.props similarity index 100% rename from build/sources.props rename to src/HttpSysServer/build/sources.props diff --git a/samples/HotAddSample/HotAddSample.csproj b/src/HttpSysServer/samples/HotAddSample/HotAddSample.csproj similarity index 100% rename from samples/HotAddSample/HotAddSample.csproj rename to src/HttpSysServer/samples/HotAddSample/HotAddSample.csproj diff --git a/samples/HotAddSample/Properties/launchSettings.json b/src/HttpSysServer/samples/HotAddSample/Properties/launchSettings.json similarity index 100% rename from samples/HotAddSample/Properties/launchSettings.json rename to src/HttpSysServer/samples/HotAddSample/Properties/launchSettings.json diff --git a/samples/HotAddSample/Startup.cs b/src/HttpSysServer/samples/HotAddSample/Startup.cs similarity index 100% rename from samples/HotAddSample/Startup.cs rename to src/HttpSysServer/samples/HotAddSample/Startup.cs diff --git a/samples/SelfHostServer/App.config b/src/HttpSysServer/samples/SelfHostServer/App.config similarity index 100% rename from samples/SelfHostServer/App.config rename to src/HttpSysServer/samples/SelfHostServer/App.config diff --git a/samples/SelfHostServer/Properties/launchSettings.json b/src/HttpSysServer/samples/SelfHostServer/Properties/launchSettings.json similarity index 100% rename from samples/SelfHostServer/Properties/launchSettings.json rename to src/HttpSysServer/samples/SelfHostServer/Properties/launchSettings.json diff --git a/samples/SelfHostServer/Public/1kb.txt b/src/HttpSysServer/samples/SelfHostServer/Public/1kb.txt similarity index 100% rename from samples/SelfHostServer/Public/1kb.txt rename to src/HttpSysServer/samples/SelfHostServer/Public/1kb.txt diff --git a/samples/SelfHostServer/SelfHostServer.csproj b/src/HttpSysServer/samples/SelfHostServer/SelfHostServer.csproj similarity index 100% rename from samples/SelfHostServer/SelfHostServer.csproj rename to src/HttpSysServer/samples/SelfHostServer/SelfHostServer.csproj diff --git a/samples/SelfHostServer/Startup.cs b/src/HttpSysServer/samples/SelfHostServer/Startup.cs similarity index 100% rename from samples/SelfHostServer/Startup.cs rename to src/HttpSysServer/samples/SelfHostServer/Startup.cs diff --git a/samples/TestClient/App.config b/src/HttpSysServer/samples/TestClient/App.config similarity index 100% rename from samples/TestClient/App.config rename to src/HttpSysServer/samples/TestClient/App.config diff --git a/samples/TestClient/Program.cs b/src/HttpSysServer/samples/TestClient/Program.cs similarity index 100% rename from samples/TestClient/Program.cs rename to src/HttpSysServer/samples/TestClient/Program.cs diff --git a/samples/TestClient/Properties/AssemblyInfo.cs b/src/HttpSysServer/samples/TestClient/Properties/AssemblyInfo.cs similarity index 100% rename from samples/TestClient/Properties/AssemblyInfo.cs rename to src/HttpSysServer/samples/TestClient/Properties/AssemblyInfo.cs diff --git a/samples/TestClient/TestClient.csproj b/src/HttpSysServer/samples/TestClient/TestClient.csproj similarity index 100% rename from samples/TestClient/TestClient.csproj rename to src/HttpSysServer/samples/TestClient/TestClient.csproj diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs b/src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs similarity index 100% rename from shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs rename to src/HttpSysServer/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs diff --git a/src/Directory.Build.props b/src/HttpSysServer/src/Directory.Build.props similarity index 100% rename from src/Directory.Build.props rename to src/HttpSysServer/src/Directory.Build.props diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationHandler.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationSchemes.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationSchemes.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationSchemes.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationSchemes.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/FeatureContext.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Helpers.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Http503VerbosityLevel .cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysDefaults.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysException.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/LogHelper.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ComNetOS.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysSettings.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/IntPtrHelper.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/IntPtrHelper.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/IntPtrHelper.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/IntPtrHelper.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Properties/AssemblyInfo.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Properties/Resources.Designer.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/BoundaryType.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/BoundaryType.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/BoundaryType.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/BoundaryType.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpReasonPhrase.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpReasonPhrase.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpReasonPhrase.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpReasonPhrase.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/OpaqueStream.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.tt b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.tt similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.tt rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.tt diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Resources.resx b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Resources.resx similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/Resources.resx rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/Resources.resx diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/ResponseStream.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/StandardFeatureCollection.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefixCollection.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/ValidationHelper.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/ValidationHelper.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/ValidationHelper.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/ValidationHelper.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/WebHostBuilderHttpSysExtensions.cs diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json b/src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json similarity index 100% rename from src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json rename to src/HttpSysServer/src/Microsoft.AspNetCore.Server.HttpSys/baseline.netcore.json diff --git a/test/Directory.Build.props b/src/HttpSysServer/test/Directory.Build.props similarity index 100% rename from test/Directory.Build.props rename to src/HttpSysServer/test/Directory.Build.props diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/AuthenticationTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/DummyApplication.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/HttpsTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/AuthenticationTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/HttpsTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/OpaqueUpgradeTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestHeaderTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseCachingTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseHeaderTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/Utilities.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OSDontSkipConditionAttribute.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/OpaqueUpgradeTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Properties/AssemblyInfo.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestHeaderTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseCachingTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseHeaderTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseSendFileTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.Tests/Microsoft.AspNetCore.Server.HttpSys.Tests.csproj diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs b/src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs rename to src/HttpSysServer/test/Microsoft.AspNetCore.Server.HttpSys.Tests/UrlPrefixTests.cs diff --git a/version.props b/src/HttpSysServer/version.props similarity index 100% rename from version.props rename to src/HttpSysServer/version.props